您的位置:首页 > 编程语言 > PHP开发

php类和对象总结

2017-05-27 13:03 295 查看
1. __construct:      内置构造函数,在对象被创建时自动调用。见如下代码:
<?php
class ConstructTest {
private $arg1;
private $arg2;

public function __construct($arg1, $arg2) {
$this->arg1 = $arg1;
$this->arg2 = $arg2;
print "__construct is called...\n";
}
public function printAttributes() {
print '$arg1 = '.$this->arg1.' $arg2 = '.$this->arg2."\n";
}
}
$testObject = new ConstructTest("arg1","arg2");
$testObject->printAttributes();
     运行结果如下:
Stephens-Air:Desktop$ php Test.php
__construct is called...
$arg1 = arg1 $arg2 = arg2
2. parent:      用于在子类中直接调用父类中的方法,功能等同于Java中的super。 
<?php
class BaseClass {
protected $arg1;
protected $arg2;

function __construct($arg1, $arg2) {
$this->arg1 = $arg1;
$this->arg2 = $arg2;
print "__construct is called...\n";
}
function getAttributes() {
return '$arg1 = '.$this->arg1.' $arg2 = '.$this->arg2;
}
}

class SubClass extends BaseClass {
protected $arg3;

function __construct($baseArg1, $baseArg2, $subArg3) {
parent::__construct($baseArg1, $baseArg2);
$this->arg3 = $subArg3;
}
function getAttributes() {
return parent::getAttributes().' $arg3 = '.$this->arg3;
}
}
$testObject = new SubClass("arg1","arg2","arg3");
print $testObject->getAttributes()."\n";
     运行结果如下:
Stephens-Air:Desktop$ php Test.php
__construct is called...
$arg1 = arg1 $arg2 = arg2 $arg3 = arg3
3. self:     在类内调用该类静态成员和静态方法的前缀修饰,对于非静态成员变量和函数则使用this。 
<?php
class StaticExample {
static public $arg1 = "Hello, This is static field.\n";
static public function sayHello() {
print self::$arg1;
}
}

print StaticExample::$arg1;
StaticExample::sayHello();
     运行结果如下:
Stephens-Air:Desktop$ php Test.php
Hello, This is static field.
Hello, This is static field.
4. static:     这里介绍的static关键字主要用于PHP 5.3以上版本新增的延迟静态绑定功能。请看一下代码和关键性注释。
<?php
abstract class Base {
public static function getInstance() {
//这里的new static()实例化的是调用该静态方法的当前类。
return new static();
}
abstract public function printSelf();
}

class SubA extends Base {
public function printSelf() {
print "This is SubA::printSelf.\n";
}
}

class SubB extends Base {
public function printSelf() {
print "This is SubB::printSelf.\n";
}
}

SubA::getInstance()->printSelf();
SubB::getInstance()->printSelf();
     运行结果如下:
Stephens-Air:Desktop$ php Test.php
This is SubA::printSelf.
This is SubB::printSelf.
     static关键字不仅仅可以用于实例化。和self和parent一样,static还可以作为静态方法调用的标识符,甚至是从非静态上下文中调用。在该场景下,self仍然表示的是当前方法所在的类。见如下代码: 
<?php
abstract class Base {
private $ownedGroup;
public function __construct() {
//这里的static和上面的例子一样,表示当前调用该方法的实际类。
//需要另外说明的是,这里的getGroup方法即便不是静态方法,也会得到相同的结果。然而倘若
//getGroup真的只是普通类方法,那么这里还是建议使用$this。
$this->ownedGroup = static::getGroup();
}
public function printGroup() {
print "My Group is ".$this->ownedGroup."\n";
}
public static function getInstance() {
return new static();
}
public static function getGroup() {
return "default";
}
}

class SubA extends Base {
}

class SubB extends Base {
public static function getGroup() {
return "SubB";
}
}

SubA::getInstance()->printGroup();
SubB::getInstance()->printGroup(); 
     运行结果如下:
Stephens-Air:Desktop$ php Test.php
My Group is default
My Group is SubB
5. __destruct:     析构方法的作用和构造方法__construct刚好相反,它只是在对象被垃圾收集器收集之前自动调用,我们可以利用该方法做一些必要的清理工作。
<?php
class TestClass {
function __destruct() {
print "TestClass destructor is called.\n";
}
}

$testObj = new TestClass();
unset($testObj);
print "Application will exit.\n";
     运行结果如下:
Stephens-Air:Desktop$ php Test.php
TestClass destructor is called.
Application will exit.
6. __clone:     在PHP 5之后的版本中,对象之间的赋值为引用赋值,即赋值后的两个对象将指向同一地址空间,如果想基于对象赋值,可以使用PHP提供的clone方法。该方法将当前对象浅拷贝之后的副本返回,如果想在clone的过程中完成一些特殊的操作,如深拷贝,则需要在当前类的声明中实现__clone方法,该方法在执行clone的过程中会被隐式调用。另外需要格外注意的是,__clone方法是作用再被拷贝的对象上,即赋值后的对象上执行。
<?php
class InnerClass {
public $id = 10;
public function printSelf() {
print '$id = '.$this->id."\n";
}
}

class OuterClass {
public $innerClass;
public function __construct() {
$this->innerClass = new InnerClass();
}
public function __clone() {
$this->innerClass = clone $this->innerClass;
print "__clone is called.\n";
}
}

$outerA = new OuterClass();
print "Before calling to clone.\n";
$outerB = clone $outerA;
print "After calling to clone.\n";
$outerA->innerClass->id = 20;
print "In outerA: ";
$outerA->innerClass->printSelf();
print "In outerB: ";
$outerB->innerClass->printSelf();
     运行结果如下:
Stephens-Air:Desktop$ php Test.php
Before calling to clone.
__clone is called.
After calling to clone.
In outerA: $id = 20
In outerB: $id = 10
7. const:    PHP5可以在类中定义常量属性。和全局常量一样,一旦定义就不能改变。常量属性不需要像普通属性那样以$开头,按照惯例,只能用大写字母来命名常量。另外和静态属性一样,只能通过类而不能通过类的实例访问常量属性,引用常量时同样也不需要以$符号作为前导符。另外常量只能被赋值为基础类型,如整型,而不能指向任何对象类型。
<?php
class TestClass {
const AVAILABLE = 0;
}

print "TestClass::AVAILABLE = ".TestClass::AVAILABLE."\n";
    运行结果如下:
0Stephens-Air:Desktop$ php Test.php
TestClass::AVAILABLE = 0
1. __toString:    当对象被打印时,如果该类定义了该方法,则打印该方法的返回值,否则将按照PHP的缺省行为输出打印结果。该方法类似于Java中的toString()。
<?phpclass TestClass {public function __toString() {return "This is TestClass::__toString.\n";}}$testObj = new TestClass();print $testObj;
    运行结果如下:
Stephens-Air:Desktop$ php Test.phpThis is TestClass::__toString.
2. __get和__set:    这两个方法用于处理类中未声明的属性访问。当对象使用者试图访问未声明的对象属性时,__get()会被调用,并带有一个包含要访问的属性名称字符串作为参数。无论从__get()方法返回什么,都会直接返回给调用者,就如同带有该值的属性存在一样。另外需要注意的是,如果属性存在,但是其访问可见性为private或protected,那么这两个拦截方法同样会被调用,反之,如果属性存在切可访问,那么直接访问属性即可,这两个方法将不再会被调用。以下为__get()拦截方法的示例代码:
<?phpclass TestClass {private $privateField;public $publicField;public function __construct() {$this->privateField = "This is a private Field.\n";$this->publicField = "This is a public Field.\n";}public function __get($property) {print "__get() is called.\n";$method = "get${property}";if (method_exists($this, $method)) {return $this->$method();}return "This is undefined field.\n";}public function getPrivateField() {return $this->privateField;}}$testObj = new TestClass();print $testObj->privateField;print $testObj->undefinedField;print $testObj->publicField;
    运行结果如下:
Stephens-Air:Desktop$ php Test.php__get() is called.This is a private Field.__get() is called.This is undefined field.This is a public Field.
    __set()方法被调用的规则和__get()基本相同,差别是用于拦截未定义或不可见类属性的赋值操作。另外,该方法接收两个参数,分别是属性名称和要设定的值。见如下代码示例:
<?phpclass TestClass {private $privateField;public $publicField;public function __construct() {$this->privateField = "This is a private Field.\n";$this->publicField = "This is a public Field.\n";}public function __get($property) {print "__get() is called.\n";$method = "get${property}";if (method_exists($this, $method)) {return $this->$method();}return "This is an undefined field.\n";}public function __set($property, $value) {print "__set is called.\n";$method = "set${property}";if (method_exists($this, $method)) {$this->$method($value);} else {print "This is an undefined field.\n";}}public function getPrivateField() {return $this->privateField;}public function setPrivateField($value) {$this->privateField = $value;}}$testObj = new TestClass();$testObj->privateField = "This is a private Field after set.\n";$testObj->undefinedField = "This is a undefined Field after set.\n";$testObj->publicField = "This is a public Field after set.\n";print $testObj->privateField;print $testObj->undefinedField;print $testObj->publicField;
    运行结果如下:
Stephens-Air:Desktop$ php Test.php__set is called.__set is called.This is an undefined field.__get() is called.This is a private Field after set.__get() is called.This is an undefined field.This is a public Field after set.
3. __isset和__unset:    这两个拦截方法被调用的规则和__get()和__set()非常类似,只是用于类中不存在或不可见属性被isset()和unset()两个全局方法应用时才会被分别触发。 
<?phpclass TestClass {private $privateField;public $publicField;public function __construct() {$this->privateField = "Defined private field";$this->publicField = "Defined public field";}public function __isset($property) {print "__isset is called.\n";return isset($this->$property);}public function __unset($property) {print "__unset is called.\n";if (isset($this->$property)) {unset($this->$property);}}}$testObj = new TestClass();print 'isset($testObj->privateField) is '.(isset($testObj->privateField) ? "true" : "false")."\n";print 'isset($testObj->undefinedField) is '.(isset($testObj->undefinedField) ? "true" : "false")."\n";print 'isset($testObj->publicField) is '.(isset($testObj->publicField) ? "true" : "false")."\n";print "After unset......\n";//下面两个函数调用后,$testObj的两个对象属性均会变为不可用。//另外从输出结果来看,__unset方法仅仅被调用一次,因为publicField为可见属性,所以__unset不会因该属性而被调用。unset($testObj->privateField);unset($testObj->publicField);print 'isset($testObj->privateField) is '.(isset($testObj->privateField) ? "true" : "false")."\n";print 'isset($testObj->publicField) is '.(isset($testObj->publicField) ? "true" : "false")."\n";
    运行结果如下:
Stephens-Air:Desktop$ php Test.php__isset is called.isset($testObj->privateField) is true__isset is called.isset($testObj->undefinedField) is falseisset($testObj->publicField) is trueAfter unset......__unset is called.__isset is called.isset($testObj->privateField) is false__isset is called.isset($testObj->publicField) is false
4. __call:    __call()方法是一个非常有用但又非常容易被滥用的拦截方法。当对象使用者试图访问当前对象未定义的成员函数时,__call()会被自动调用,同时传递两个参数,分别为函数名称和传递给调用函数的所有参数(数组)。__call方法返回的任何值都会返回给函数调用者,就如同该成员函数真实存在一样。下面给出一个非常有用的委托示例。 
<?phpclass DelegateClass {function printMessage($arg1, $arg2) {print "DelegateClass:delegatedMethod is called.\n";print '$arg1 = '.$arg1.'and $arg2 = '.$arg2."\n";}}class TestClass {private $delegateObj;public function __construct() {$this->delegateObj = new DelegateClass();}public function __call($method, $args) {$this->delegateObj->$method($args[0],$args[1]);}}$testObj = new TestClass();$testObj->printMessage("hello","world");
    运行结果如下:
Stephens-Air:Desktop$ php Test.phpDelegateClass:delegatedMethod is called.$arg1 = helloand $arg2 = world
    从以上示例可以看出,TestClass并未声明printMessage成员方法,但是通过__call()方法的巧妙桥接直接传递给了委托对象。个人认为该技巧为双刃剑,切勿过度使用。5. 回调函数:     回调函数的应用场景无须多述,在C/C++中充斥着无数的回调函数典型用例。 这里只是简单给出PHP中回调函数的使用规则。见如下示例代码和关键性注释: 
<?phpclass Product {public $name;public $price;public function __construct($name, $price) {$this->name = $name;$this->price = $price;}}class ProcessSale {private $callbacks;function registerCallback($cb) {if (!is_callable($cb)) {throw new Exception("callback not callable.");}$this->callbacks[] = $cb;}function sale($product) {print "{$product->name}: processing \n";foreach ($this->callbacks as $cb) {//以下两种调用方式均可。call_user_func($cb, $product);$cb($product);}}}$logger = function($product) {print "    logging ({$product->name})\n";};$processor = new ProcessSale();$processor->registerCallback($logger);$processor->sale(new Product("shoes",6));print "\n";$processor->sale(new Product("coffee",6));
    运行结果如下:
Stephens-Air:Desktop$ php Test.phpshoes: processinglogging (shoes)logging (shoes)coffee: processinglogging (coffee)logging (coffee)
6. use(闭包):    在Javascript中存在大量的闭包应用,PHP中的闭包则是通过use关键字来完成的。对于闭包这个概念本身而言,简要的说就是函数内的代码可以访问其父作用域中的变量。见如下示例代码和关键性注释:
<?phpclass Product {public $name;public $price;public function __construct($name, $price) {$this->name = $name;$this->price = $price;}}class ProcessSale {private $callbacks;function registerCallback($cb) {if (!is_callable($cb)) {throw new Exception("callback not callable.");}$this->callbacks[] = $cb;}function sale($product) {print "{$product->name}: processing \n";foreach ($this->callbacks as $cb) {$cb($product);}}}class Totalizer {static function warnAmount($amt) {$count = 0;//注意这里的$amt和$count均为闭包变量,其中&$count是以引用的形式传递的,即一旦函数内部修改了该变量的值,//那么下次再访问该闭包变量时,$count将为之前调用中修改后的值。return function($product) use($amt, &$count) {$count += $product->price;print "     count: $count\n";if ($count > $amt) {print "     high price reached: {$count}\n";}};}}$processor = new ProcessSale();$processor->registerCallback(Totalizer::warnAmount(8));$processor->sale(new Product("shoes",6));$processor->sale(new Product("coffee",6));
    运行结果如下:
shoes: processingcount: 6coffee: processingcount: 12high price reached: 12
1. namespace:    和C++中的名字空间很像,作用也一样,都是为了避免在引用较多第三方库时而带来的名字冲突问题。通过名字空间,即便两个class的名称相同,但是因为位于不同的名字空间内,他们仍然可以被精确定位和区分。第一次看到PHP的名字空间语法时,感觉和C++相比在语法上是非常非常相似的,然而在写点儿小例子做做实验的时候才发现,他们的差别还是很大的,为了避免以后忘记,所以这里特别将其记录了下来。见如下代码:
<?php//in Test2.phpnamespace nstest\test2;class Test2 {public static function printMe() {print 'This is nstest\test2\Test2::printSelf.'."\n";}}<?php//in Test1.phpnamespace nstest\test1;class Test1 {public static function printMe() {print 'This is nstest\test1\Test1::printSelf.'."\n";}}require "Test2.php";nstest\test2\Test2::printMe();
    运行结果如下:
bogon:TestPhp$ php Test1.phpPHP Fatal error:  Class 'nstest\test1\nstest\test2\Test2' not found in /Users/liulei/PhpstormProjects/TestPhp/Test1.php on line 13
    是不是这个结果比较出乎意料,原因在哪呢?HOHO,原来PHP在进行名字空间引用的时候,如果名字空间的第一个字符不是前导斜杠(\),那么就被自动识别为相对名字空间,在上面的代码中,Test1自身所在的名字空间是namespace nstest\test1,因此在以nstest\test2\Test2::printMe()方式调用Test2::printMe()时,PHP将自动解析为nstest\test1\nstest\test2\Test2::printMe(),即认为nstest\test2是在当前名字空间内部的。修正该问题非常简单,只需在引用时加上前导斜杠(\)即可,见以下修复后的代码:     
<?php//Test2.phpnamespace nstest\test2;class Test2 {public static function printMe() {print 'This is nstest\test2\Test2::printSelf.'."\n";}}<?php//Test1.phpnamespace nstest\test1;class Test1 {public static function printMe() {print 'This is nstest\test1\Test1::printSelf.'."\n";}}require "Test2.php";\nstest\test2\Test2::printMe();
    运行结果如下:
bogon:TestPhp$ php Test1.phpThis is nstest\test2\Test2::printSelf.
    还有一种改动方式,可以示意一下PHP中名字空间中的相对引用。这里我们可以将Test1的名字空间改为namespace nstest,其他的修改见以下代码中红色高亮部分:
<?php//Test2.phpnamespace nstest\test2;class Test2 {public static function printMe() {print 'This is nstest\test2\Test2::printSelf.'."\n";}}<?php//Test1.phpnamespace nstest;class Test1 {public static function printMe() {print 'This is nstest\test1\Test1::printSelf.'."\n";}}require "Test2.php";test2\Test2::printMe(); 
    运行结果等于上面正确的结果。最重要的差别就是该例使用了PHP名字空间中的相对定位。相信熟悉C++的开发者一定会想到use关键字,PHP也提供了该关键字,他们的功能是一致的,都是为了避免在后面的代码中,无需再通过全限定符(类名前加名字空间前缀)来引用其他名字空间中的类了。至于具体的语法规则,还是看看下面具体的代码和关键性注释吧。
<?php//Test2.phpnamespace nstest\test2;class Test2 {public static function printMe() {print 'This is nstest\test2\Test2::printSelf.'."\n";}}<?php//Test1.phpnamespace nstest\test1;class Test1 {public static function printMe() {print 'This is nstest\test1\Test1::printSelf.'."\n";}}require "Test2.php";//这里需要特别注意的是,nstest\test2已经表示名字空间绝对路径定位,不需要再加前导斜杠(\)了。//另外这里还有一个隐式规则是test2表示该名字空间的缺省别名,在引用其名字空间内的对象时需要加test2前缀。use nstest\test2;test2\Test2::printMe();//这里我们也可以给名字空间显式的指定别名,如:use nstest\test2 as test2_alias;test2_alias\Test2::printMe(); 
    运行结果如下:
bogon:TestPhp$ php Test1.phpThis is nstest\test2\Test2::printSelf.This is nstest\test2\Test2::printSelf.
    最后介绍一下PHP中全局名字空间的引用方式,见如下代码和关键性注释:
<?phpclass Test {public static function printMe() {print 'This is Global namespace Test::printSelf.'."\n";}}//下面两行代码表示的是同一对象,即全局名字空间下的Test类,然而如果因为名字空间冲突导致第一种方式不能被PHP//编译器正常识别,那么就可以使用第二种方式显式的通知PHP,自己要引用的是全局名字空间中的Test类。Test::printMe();\Test::printMe();
    运行结果如下:
bogon:TestPhp$ php Test1.phpThis is Global namespace Test::printSelf.This is Global namespace Test::printSelf.
2. Reflection:    PHP中的反射和Java中java.lang.reflect包提供的功能一样,更有意思的是,就连很多方法命名和调用方式也是非常雷同的。他们都是由一些列可以分析类、类方法和方法参数的PHP内置类组成。我们这里主要介绍的是如下几个常用的内置类:(Reflection、RelectionClass、ReflectionMethod、ReflectionParameter和ReflectionProperty)。现在我们还是一步一步来理解,即从ReflectionClass开始给出示例代码和关键性注释: 
<?phpclass TestClass {public $publicVariable;function publicMethod() {print "This is publicMethod.\n";}}function classInfo(ReflectionClass $c) {$details = "";//getName将返回实际的类名。$name = $c->getName();if ($c->isUserDefined()) {$details .= "$name is user defined.\n";}if ($c->isInternal()) {$details .= "$name is built-in.\n";}if ($c->isAbstract()) {$details .= "$name is abstract class.\n";}if ($c->isFinal()) {$details .= "$name is final class.\n";}if ($c->isInstantiable()) {$details .= "$name can be instantiated.\n";} else {$details .= "$name cannot be instantiated.\n";}return $details;}function classSource(ReflectionClass $c) {$path = $c->getFileName();$lines = @file($path);//获取类定义代码的起始行和截至行。$from = $c->getStartLine();$to = $c->getEndLine();$len = $to - $from + 1;return implode(array_slice($lines,$from - 1,$len));}print "The following is Class Information.\n";print classInfo(new ReflectionClass('TestClass'));print "\nThe following is Class Source.\n";print classSource(new ReflectionClass('TestClass'));
    运行结果如下:
bogon:TestPhp$ php reflection_test.phpThe following is Class Information.TestClass is user defined.TestClass can be instantiated.The following is Class Source.class TestClass {public $publicVariable;function publicMethod() {print "This is publicMethod.\n";}}
    下面让我们仍然以代码示例和关键性注释的方法继续ReflectionMethod的学习之旅。<?php
class TestClass {public $publicVariable;function __construct() {}private function privateMethod() {}function publicMethod() {print "This is publicMethod.\n";}function publicMethod2(string $arg1, int $arg2) {}}//这个函数中使用的ReflectionMethod中的方法都是非常简单直观的,就不再过多赘述了。function methodInfo(ReflectionMethod $m) {$name = $m->getName();$details = "";if ($m->isUserDefined()) {$details .= "$name is user defined.\n";}if ($m->isInternal()) {$details .= "$name is built-in.\n";}if ($m->isAbstract()) {$details .= "$name is abstract.\n";}if ($m->isPublic()) {$details .= "$name is public.\n";}if ($m->isProtected()) {$details .= "$name is protected.\n";}if ($m->isPrivate()) {$details .= "$name is private.\n";}if ($m->isStatic()) {$details .= "$name is static.\n";}if ($m->isFinal()) {$details .= "$name is final.\n";}if ($m->isConstructor()) {$details .= "$name is constructor.\n";}if ($m->returnsReference()) {$details .= "$name returns a reference.\n";}return $details;}function methodSource(ReflectionMethod $m) {$path = $m->getFileName();$lines = @file($path);$from = $m->getStartLine();$to = $m->getEndLine();$len = $to - $from + 1;return implode(array_slice($lines, $from - 1, $len));}$rc = new ReflectionClass('TestClass');$methods = $rc->getMethods();print "The following is method information.\n";foreach ($methods as $method) {print methodInfo($method);print "\n--------------------\n";}print "The following is Method[TestClass::publicMethod] source.\n";print methodSource($rc->getMethod('publicMethod'));
    运行结果如下:
bogon:TestPhp$ php reflection_test.phpThe following is method information.__construct is user defined.__construct is public.__construct is constructor.--------------------privateMethod is user defined.privateMethod is private.--------------------publicMethod is user defined.publicMethod is public.--------------------publicMethod2 is user defined.publicMethod2 is public.--------------------The following is Method[TestClass::publicMethod] source.function publicMethod() {print "This is publicMethod.\n";}
    让我们继续ReflectionParameter吧,他表示的是成员函数的参数信息。继续看代码吧。
<?phpclass ParamClass {}class TestClass {function publicMethod() {print "This is publicMethod.\n";}function publicMethod2(ParamClass $arg1, &$arg2, $arg3 = null) {}}function paramInfo(ReflectionParameter $p) {$details = "";//这里的$declaringClass将等于TestClass。$declaringClass = $p->getDeclaringClass();$name = $p->getName();$class = $p->getClass();$position = $p->getPosition();$details .= "\$$name has position $position.\n";if (!empty($class)) {$classname = $class->getName();$details .= "\$$name must be a $classname object\n";}if ($p->isPassedByReference()) {$details .= "\$$name is passed by reference.\n";}if ($p->isDefaultValueAvailable()) {$def = $p->getDefaultValue();$details .= "\$$name has default: $def\n";}return $details;}$rc = new ReflectionClass('TestClass');$method = $rc->getMethod('publicMethod2');$params = $method->getParameters();foreach ($params as $p) {print paramInfo($p)."\n";}
    运行结果如下:
bogon:TestPhp$ php reflection_test.php$arg1 has position 0.$arg1 must be a ParamClass object$arg2 has position 1.$arg2 is passed by reference.$arg3 has position 2.$arg3 has default: 
    上面介绍的都是通过PHP提供的Reflection API来遍历任意class的具体信息,事实上和Java等其他语言提供的反射功能一样,PHP也同样支持通过反射类调用实际对象的方法,这里将主要应用到两个方法,分别是ReflectionClass::newInstance()来创建对象实例,另一个是ReflectionMethod::invoke(),根据对象实例和方法名执行该方法。见如下代码:
<?phpclass TestClass {private $privateArg;function __construct($arg) {$this->privateArg = $arg;}function publicMethod() {print '$privateArg = '.$this->privateArg."\n";}function publicMethod2($arg1, $arg2) {print '$arg1 = '.$arg1.' $arg2 = '.$arg2."\n";}}$rc = new ReflectionClass('TestClass');$testObj = $rc->newInstanceArgs(array('This is private argument.'));$method = $rc->getMethod('publicMethod');$method->invoke($testObj);$method2 = $rc->getMethod('publicMethod2');$method2->invoke($testObj,"hello","world");
    运行结果如下:
bogon:TestPhp$ php reflection_test.php$privateArg = This is private argument.$arg1 = hello $arg2 = world
    事实上ReflectionClass、ReflectionMethod和ReflectionParameter提供给我们的可用方法还有更多,这里只是给出几个最典型的方法,以便我们可以更为直观的学习和了解PHP Reflection API。相信再看完以后的代码示例之后,我们都会比较清楚,如果今后需要用到和class相关的功能,就从ReflectionClass中查找,而member function的信息则一定来自于ReflectionMethod,方法参数信息来自于ReflectionParameter。注:该Blog中记录的知识点,是在我学习PHP的过程中,遇到的一些PHP和其他面向对象语言相比比较独特的地方,或者是对我本人而言确实需要簿记下来以备后查的知识点。虽然谈不上什么深度,但是还是希望能与大家分享。
类和对象函数实例
1. interface_exists、class_exists、method_exists和property_exists:      顾名思义,从以上几个函数的命名便可以猜出几分他们的功能。我想这也是我随着对PHP的深入学习而越来越喜欢这门编程语言的原因了吧。下面先给出他们的原型声明和简短说明,更多的还是直接看例子代码吧。bool interface_exists (string $interface_name [, bool $autoload = true ]) 判断接口是否存在,第二个参数表示在查找时是否执行__autoload。bool class_exists (string $class_name [, bool $autoload = true ]) 判断类是否存在,第二个参数表示在查找时是否执行__autoload。bool method_exists (mixed $object , string $method_name) 判断指定类或者对象中是否含有指定的成员函数。bool property_exists (mixed $class , string $property) 判断指定类或者对象中是否含有指定的成员变量。
<?php//in another_test_class.phpinterface AnotherTestInterface {}class AnotherTestClass {public static function printMe() {print "This is Test2::printSelf.\n";}public function doSomething() {print "This is Test2::doSomething.\n";}public function doSomethingWithArgs($arg1, $arg2) {print 'This is Test2::doSomethingWithArgs with ($arg1 = '.$arg1.' and $arg2 = '.$arg2.").\n";}}<?php//in class_exist_test.php, 下面测试代码中所需的类和接口位于another_test_class.php,//由此可以发现规律,类和接口的名称是驼峰风格的,而文件名的单词间是下划线分隔的。//这里给出了两种__autoload的方式,因为第一种更为常用和方便,因此我们这里将第二种方式注释掉了,他们之间的差别可以查看manual。function __autoload($classname) {$nomilizedClassname = strtolower(preg_replace('/([A-Z]\w*)([A-Z]\w*)([A-Z]\w*)/','${1}_${2}_${3}',$classname));require strtolower($nomilizedClassname).".php";}//spl_autoload_register(function($classname) {//    $nomilizedClassname = strtolower(preg_replace('/([A-Z]\w*)([A-Z]\w*)([A-Z]\w*)/','${1}_${2}_${3}',$classname));//    require strtolower($nomilizedClassname).".php";//});print "The following case is tested before executing autoload.\n";if (!class_exists('AnotherTestClass',false)) {print "This class doesn't exist if no autoload.\n";}if (!interface_exists('AnotherTestInterface',false)) {print "This interface doesn't exist if no autoload.\n";}print "\nThe following case is tested after executing autoload.\n";if (class_exists('AnotherTestClass',true)) {print "This class exists if autoload is set to true.\n";}if (interface_exists('AnotherTestInterface',true)) {print "This interface exists if autoload is set to true.\n";} 
    运行结果如下: 
bogon:TestPhp$ php class_exist_test.phpThe following case is tested before executing autoload.This class doesn't exist if no autoload.This interface doesn't exist if no autoload.The following case is tested after executing autoload.This class exists if autoload is set to true.This interface exists if autoload is set to true.
2. get_declared_classes和get_declared_interfaces:     分别返回当前可以访问的所有类和接口,这不仅包括自定义类和接口,也包括了PHP内置类和接口。他们的函数声明非常简单,没有参数,只是返回数组。见如下代码:
<?phpinterface AnotherTestInterface {}class AnotherTestClass {public static function printMe() {print "This is Test2::printSelf.\n";}}print_r(get_declared_interfaces());print_r(get_declared_classes());
    由于输出结果过长,而且这两个函数也比较简单,所以下面就不再给出输出结果了。3. get_class_methods、get_class_vars和get_object_vars:     这三个函数有一个共同点,即只能获取作用域可见范围内的所有成员函数、成员变量或非静态成员变量。比如在类的内部调用,则所有成员函数或者变量都符合条件,而在类的外部,则只有共有的函数和变量可以返回。array get_class_methods (mixed $class_name) 获取指定类中可访问的成员函数。array get_class_vars (string $class_name) 获取指定类中可以访问的成员变量。array get_object_vars (object $object) 获取可以访问的非静态成员变量。
<?phpfunction output_array($functionName, $items) {print "$functionName.....................\n";foreach ($items as $key => $value) {print '$key = '.$key. ' => $value = '.$value."\n";}}class TestClass {public $publicVar = 1;private $privateVar = 2;static private $staticPrivateVar = "hello";static public $staticPublicVar;private function privateFunction() {}function publicFunction() {output_array("get_class_methods",get_class_methods(__CLASS__));output_array('get_class_vars',get_class_vars(__CLASS__));output_array('get_object_vars',get_object_vars($this));}}$testObj = new TestClass();print "The following is output within TestClass.\n";$testObj->publicFunction();print "\nThe following is output out of TestClass.\n";output_array('get_class_methods',get_class_methods('TestClass'));output_array('get_class_vars',get_class_vars('TestClass'));output_array('get_object_vars',get_object_vars($testObj));
    运行结果如下:
bogon:TestPhp liulei$ php class_exist_test.phpThe following is output within TestClass.get_class_methods.....................$key = 0 => $value = privateFunction$key = 1 => $value = publicFunctionget_class_vars.....................$key = publicVar => $value = 1$key = privateVar => $value = 2$key = staticPrivateVar => $value = hello$key = staticPublicVar => $value =get_object_vars.....................$key = publicVar => $value = 1$key = privateVar => $value = 2The following is output out of TestClass.get_class_methods.....................$key = 0 => $value = publicFunctionget_class_vars.....................$key = publicVar => $value = 1$key = staticPublicVar => $value =get_object_vars.....................$key = publicVar => $value = 1
4. get_called_class和get_class:string get_class ([ object $object = NULL ]) 获取参数对象的类名称。string get_called_class (void) 静态方法调用时当前的类名称。
<?phpclass Base {static public function test() {var_dump(get_called_class());}}class Derive extends Base {}Base::test();Derive::test();var_dump(get_class(new Base()));var_dump(get_class(new Derive()));
    运行结果如下:
bogon:TestPhp$ php another_test_class.phpstring(4) "Base"string(6) "Derive"string(4) "Base"string(6) "Derive"
5. get_parent_class、is_a和is_subclass_of:    这三个函数都是和类的继承相关,所以我把他们归到了一起。string get_parent_class ([ mixed $object ]) 获取参数对象的父类,如果没有父类则返回false。bool is_a (object $object, string $class_name) 判断第一个参数对象是否是$class_name类本身或是其父类的对象。bool is_subclass_of (mixed $object, string $class_name) 判断第一个参数对象是否是$class_name的子类。
<?phpclass Base {static public function test() {var_dump(get_called_class());}}class Derive extends Base {}var_dump(get_parent_class(new Derive()));var_dump(is_a(new Derive(),'Derive'));var_dump(is_a(new Derive(),'Base'));var_dump(is_a(new Base(),'Derive'));var_dump(is_subclass_of(new Derive(),'Derive'));var_dump(is_subclass_of(new Derive(),'Base'));
    运行结果如下:
bogon:TestPhp$ php another_test_class.phpstring(4) "Base"bool(true)bool(true)bool(false)bool(false)bool(true)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: