객체 복제
객체 순회
객체 직렬화 및 역직렬화
내장 표준 클래스 사용
특성 사용
클래스 및 객체 관련 기능
PHP 반사 메커니즘
PHP의 객체지향은 중요한 지식 포인트이며, PHP의 아이디어는 개발 전 과정에 걸쳐 실행됩니다. 객체 복제 및 객체 순회, 객체 직렬화 및 역직렬화의 특성과 같이 객체 지향에 대해 이해해야 할 몇 가지 지식 포인트가 있습니다. PHP 프레임워크를 작성하려면 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 $就对象;
위 결과에서 알 수 있듯이 객체의 데이터가 변경됩니다. 개체는 다른 개체의 데이터에 영향을 미치지 않습니다. 객체 복제는 완전히 새로운 객체를 생성합니다.
PHP의 매직 메소드 중에 복사가 완료되면 __clone()이라는 매직 메소드가 있습니다. 이는 클래스에 정의되어 있습니다. 매직 메소드 __clone() 메소드가 사용되면 새로 생성되거나 복사된 객체는 이 __clone() 메소드를 호출합니다. 이 메소드에서는 필요한 경우 속성을 일부 변경할 수 있습니다.
객체 복제를 원하지 않는 경우 내부적으로 __clone() 매직 메서드를 비공개로 정의할 수 있습니다. 이때 복제하는 경우
Call to private Peoson::__clone() from context ''
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
<?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));
위 코드를 실행하면 D 드라이브에 문자열로 변환된 객체가 포함된 person.txt 파일이 있는 것을 확인할 수 있습니다.
<?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 $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)!