#物件的複製
物件的遍歷
物件的序列化與反序列化
#內建標準類別的使用
traits的使用
類別和物件的相關函數
#PHP反射機制
物件的複製
當我們建立一個物件後,就會在記憶體中分配一個空間,物件名稱指向這個空間,前面我們講過物件的賦值,當一個物件把裡面的資料修改了,另一個物件的資料也會跟著變化,因為賦值是相當於把物件識別碼賦值了一份,而克隆並不是這樣的。
<?php class Person{ public $name; public $age; public $sex; public function __construct($name,$age,$sex){ $this -> name = $name; $this -> age = $age; $this -> sex = $sex; } public function getName(){ return $this -> name; } public function getAge(){ return $this -> age; } public function getSex(){ return $this -> sex; } } $a = new Person('宋江','45','男'); echo '<pre class="brush:php;toolbar:false">'; $b = clone $a; $b -> name = '武松'; var_dump($a); var_dump($b);
結果
$新对象 = clone $就对象;
Call to private Peoson::__clone() from context ''
物件的遍歷
在PHP中物件也是可以遍歷的,物件的遍歷可以理解成把某個物件的屬性和值,遍歷顯示出來。遍歷使用到foreach這個迴圈體。基本語法:foreach(对象名 as $key => $val){ //$key是属性名,$val是属性值 }
<?php class Person{ public $name; public $age; private $sex; public function __construct($name,$age,$sex){ $this -> name = $name; $this -> age = $age; $this -> sex = $sex; } } $person = new Person('孙悟空',256,'男'); foreach ($person as $key => $value) { echo $key . ' = ' . $value . '<br>'; } .......结果........ name = 孙悟空 age = 256
物件的遍歷只能把屬性的修飾符是public的遍歷出來,protected和private不能再類外訪問,所以在類別外進行物件的遍歷,用這兩個修飾符修飾的屬性是取不出來的,就像上面程式碼的sex屬性一樣。
物件的序列化和反序列化
在PHP中當程式執行完一個文件,就會自動的釋放內存,我們在文件中創建的對象,變數等,都會消失,如果我們在一個文件創建了一個對象,在另外一個對像中想要使用這個對象,就可以使用到對象的序列化(serialize())和反序列化(unserialize()) 。
對象的序列化和反序列化可以理解成把對象轉換成字串保存在一個文件中,在用到對象時把文件進行反序列化得到對象,對像是不能直接保存在文件中的。
示意圖:a.php文件,建立一個物件並儲存:###
<?php class Person{ public $name; public $age; private $sex; public function __construct($name,$age,$sex){ $this -> name = $name; $this -> age = $age; $this -> sex = $sex; } } $person = new Person('孙悟空',256,'男'); //使用file_put_contents()函数把将一个字符串写入文件 file_put_contents('D:person.txt', serialize($person));
<?php class Person{ public $name; public $age; private $sex; public function __construct($name,$age,$sex){ $this -> name = $name; $this -> age = $age; $this -> sex = $sex; } } //通过file_get_contents这个方法把一个文件读取到字符串。 $str = file_get_contents('D:person.txt'); //进行反序列化。 $person = unserialize($str); echo '<pre class="brush:php;toolbar:false">'; var_dump($person); ......结果...... object(Person)#1 (3) { ["name"]=> string(9) "孙悟空" ["age"]=> int(256) ["sex":"Person":private]=> string(3) "男" }
PHP內建標準類
有時我們希望把一些數據,以物件的屬性的方式存儲,同時我們又不想定義一個類,可以考慮使用PHP內置標準類stdClass,這是用系統提供的一個虛擬的類,並不需要我們定義就可以直接使用。
<?php $person = new StdClass(); $person -> name = '孙悟空'; $person -> age = 524; $person -> sex = '男'; echo '<pre class="brush:php;toolbar:false">'; var_dump($person); ......结果...... object(stdClass)#1 (3) { ["name"]=> string(9) "孙悟空" ["age"]=> int(524) ["sex"]=> string(3) "男" }
traits使用语法:
trait 自定义名称{ //额外定义的代码 } 在类中使用格式 use 自定义的名称;
代码:
<?php //使用trait,自定义名称 trait my_code{ public function minus($num1,$num2){ return $num1 - $num2; } } class A{ public function plus($num1,$num2){ return $num1 + $num2; } } class B extends A{ //使用trait定义的代码块 use my_code; } class C extends A{ use my_code; } class D extends A{ } $b = new B(); $c = new C(); $d = new D(); echo $b -> plus(1,2); echo '<br>'; echo $b -> minus(2,1); echo '<br>'; echo $d -> plus(1,2); echo '<br>'; echo $d -> minus(2,1); ......结果...... 3 1 3 Fatal error: Call to undefined method D::minus() in D:\mywamp\Apache24\htdocs\zendstudio\yunsuanfu\staits.php on line 36
在上面代码中类D没有使用trait代码,所以在使用minus方法时,出现错误。
当我们在trait中写的函数和父类的函数一样时,以trait代码为准,即trait代码的优先级高于继承的类。
在PHP中系统提供了一系列的函数来判断类和对象的。从帮助文档中可以看到好多函数:
在这里我们只对里面的几个函数进行了解。
<?php class Person{ public $name; public $age; private $sex; public function __construct($name,$age,$sex){ $this -> name = $name; $this -> age = $age; $this -> sex = $sex; } public function showInfo(){ echo '名字是:' . $this -> name . ',年龄是:' . $this -> age . ',性别是:' . $this -> sex . '<br>'; } } //判断是否创建了对象,没有创建返回true,创建返回false。 if(class_exists('Person')){ $person = new Person('唐僧',25,'男'); //返回对象的类名 echo '类名是: ' . get_class($person) . '<br>'; //判断方法是否存在。 if(method_exists($person, 'showInfo')){ $person -> showInfo(); }else{ echo '该方法不存在'; } //判断属性是否存在 if(property_exists($person,'name')){ echo $person -> name; }else{ echo '属性不存在'; } }else{ echo '类不存在'; } ......结果...... 类名是: Person 名字是:唐僧,年龄是:25,性别是:男 唐僧
使用类和对象函数,可以保证我们代码的完整性,对出错信息进行及时的捕获输出。
在很多编程语言中都有反射这种概念,反射简单理解就是通过类,获取里面的属性,方法,甚至注释也可以,不管属性和方法的访问修饰符是什么类型都可以获取到。
在PHP 5中具有完整的反射API,添加了对类、接口、函数、方法和扩展进行反向工程的能力。此外,反射 API 提供了方法来取出函数、类和方法中的文档注释。而我们在开发中一般是使用不到反射的,但是在某些情况下使用反射可以更好的处理问题,比如我们需要我们写框架底层,扩展功能,管理大量的未知类。
定义一个类,通过反射创建对象和调用里面的方法:
<?php class Dog{ public $name; protected $age; private $food; public function __construct($name, $age, $food){ $this->name = $name; $this->age = $age; $this->food = $food; } public function cry($sound){ echo '<br> ' . $this->name . ' 叫声是.' . $sound; } } //使用反射完成对象的创建和方法调用 //1. 创建一个反射对象 $reflect_obj = new ReflectionClass('Dog'); //2. 通过反射对象创建Dog对象实例 $dog = $reflect_obj->newInstance('大黄狗', 4, '排骨'); echo '<pre class="brush:php;toolbar:false">'; var_dump($dog); //3. 调用方法-使用代理方式. $reflect_method_cry = $reflect_obj->getMethod('cry'); echo '<pre class="brush:php;toolbar:false">'; var_dump($reflect_method_cry); //4. 代理调用cry $reflect_method_cry->invoke($dog, '汪汪');
结果:
在上面代码中,我们通过new创建了一个反射的对象,在反射对象里面通过newInstance()方法得到类的对象。获取里面的方法可以使用反射对象的getMethod()方法,返回来的是一个方法对象ReflectionMethod类,通过里面的invoke()方法执行该方法。这里只是基本的介绍,可以查找帮助文档了解更多的反射对象和方法。
需求:
有一个类IndexAction,其中的方法和访问控制修饰符是不确定的, 1. 如果index 方法是public,可以执行 _before_index. 2. 如果存在_before_index 方法,并且是public的,执行该方法 3. 执行test方法 4. 再判断有没有_after_index方法,并且是public的,执行该方法
代码:
<?php class IndexAction{ public function index(){ echo 'index<br>'; } public function _before_index(){ echo '_before_index方法执行 <br>'; } public function test($data){ echo 'data : ' . $data . '<br>'; } public function _after_index(){ echo '_after_index方法执行<br>'; } } if(class_exists('IndexAction')){ //创建对象 $reflectionClass = new ReflectionClass('IndexAction'); //判断index是否存在 if($reflectionClass -> hasMethod('index')){ //获取index方法对象 $reflec_index_method = $reflectionClass -> getMethod('index'); //判断修饰符是否是public if($reflec_index_method -> isPublic()){ //判断是否有_before_index方法 if($reflectionClass -> hasMethod('_before_index')){ $reflec_before_method = $reflectionClass -> getMethod('_before_index'); //判断是否是public if($reflec_before_method -> isPublic()){ $reflec_before_method -> invoke($reflectionClass -> newInstance()); //调用test()方法 $reflectionClass -> getMethod('test') -> invoke($reflectionClass -> newInstance(),'这是test的数据'); //判断是否有_after_index方法 if($reflectionClass -> hasMethod('_after_index')){ $reflec_after_method = $reflectionClass -> getMethod('_after_index'); //判断是否是public if($reflec_after_method -> isPublic()){ //执行_after_index方法 $reflec_after_method -> invoke($reflectionClass -> newInstance()); }else{ echo '_after_index不是public修饰的'; } }else{ echo '没有_after_index方法'; } }else{ echo '_before_index修饰符不是public'; } }else{ echo '没有_before_index方法'; } }else{ echo 'index方法不是public修饰'; } }else{ echo 'index方法不存在'; } }else{ echo '类名不存在'; } ......结果....... _before_index方法执行 data : 这是test的数据 _after_index方法执行
在上面的代码中可以看到我们不停地在判断类中有没有某个方法,是不是public修饰,然后执行,我们可以利用封装的思想,把一些共性的特征抽取出来写成一个函数。从而对我们的代码进行优化。
优化的代码:
<?php class IndexAction{ public function index(){ echo 'index<br>'; } public function _before_index(){ echo '_before_index方法执行 <br>'; } public function test($data){ echo 'data : ' . $data . '<br>'; } public function _after_index(){ echo '_after_index方法执行<br>'; } } if(class_exists('IndexAction')){ $reflectionClass = new ReflectionClass('IndexAction'); //创建IndexAction对象。 $indexAction = $reflectionClass -> newInstance(); execute($reflectionClass,$indexAction,'index'); execute($reflectionClass,$indexAction,'_after_index'); execute($reflectionClass,$indexAction,'test','test使用的数据'); execute($reflectionClass,$indexAction,'_after_index'); }else{ echo '没有IndexAction方法'; } //封装的函数 /** * [execute description]对反射的封装。 * @param [type] $reflect_obj [description]反射对象 * @param [type] $worker [description]类对象 * @param [type] $name [description]方法的名字 * @param [type] $canshu [description]方法的参数 * @return boolean [description] */ function execute($reflect_obj,$indexAction,$name,$param = ''){ if($reflect_obj-> hasMethod($name)){ $method = $reflect_obj->getMethod($name); if($method->isPublic()){ $method->invoke($indexAction,$param); }else{ echo $name . '不是public'; } }else{ echo $name . '方法不存在'; } } ......结果..... index _after_index方法执行 data : test使用的数据 _after_index方法执行
可以看到进行功能的封装,可以简化我们的代码,同时代码看起来更加的清晰。
PHP的面向对象的内容到这里算是讲完了,在开发中利用面向对象的思想进行开发是一定要掌握的技能。同时也要对面向对象进行深度的了解。
以上就是PHP,反射、对象序列化的内容,更多相关内容请关注PHP中文网(www.php.cn)!