<?php /** * Created by PhpStorm. * User: cl * Date: 2019/8/12 * Time: 7:08 */ /*oop*/ class Person{ public $name; public $gender; public function say(){ echo $this->name,'is',$this->gender; } } $student = new Person(); $student->name = "CL"; $student->gender = "MAN"; $student->say(); // CLisMAN var_dump((array)$student); // array(2) { ["name"]=> string(2) "CL" ["gender"]=> string(3) "MAN" } // 对象由属性组成,一个对象的属性是它区别于另外一个对象的关键所在。因为php的对象使用数组来模拟的 // 所以咱们把对象转成数组,就能看见这个对象所拥有的属性了。 // 到这里,能够直观的认识到,对象就是一堆数据。既然如此,能够把一个对象存储起来,以便须要时用,这就是对象的序列化。 $str = serialize($student); var_dump($str); // string(60) "O:6:"Person":2:{s:4:"name";s:2:"CL";s:6:"gender";s:3:"MAN";}" // 在须要时,能够反序列化取出这个对象 var_dump(unserialize($str)); // object(Person)#2 (2) { ["name"]=> string(2) "CL" ["gender"]=> string(3) "MAN" } // 能够看到,对象序列化后,存储的只是对象的属性。类是由属性和方法组成的,而对象则是属性的集合,由同一个类生成的不一样对象, // 拥有各自不一样的属性,但共享了类的代码空间中方法区域的代码。 /*对象与数组*/ // 数组是由键值对数据组成,数组的键值对和对象的属性/属性值对十分类似。对象序列化后和数组序列化后的结果是 // 惊人的类似 $student_arr = ['name' => 'CL' , 'gender' => 'MAN']; var_dump(serialize($student_arr)); // string(49) "a:2:{s:4:"name";s:2:"CL";s:6:"gender";s:3:"MAN";}" // 区别在于 : 对象中还包含指针,指向了它所属的类。 /* 对象与类*/ // 若是对象中还包含对象,那么序列化后会是什么样子呢? class Family{ public $people; public $location; public function __construct ($p,$loc){ $this->people = $p; $this->location = $loc; } /* public function __destruct(){ var_dump('魔术方法之析构方法'); }*/ } $tom = new Family($student,"peking"); var_dump(serialize($tom)); // string(118) "O:6:"Family":2:{s:6:"people";O:6:"Person":2:{s:4:"name";s:2:"CL";s:6:"gender";s:3:"MAN";}s:8:"location";s:6:"peking";}" /* 能够看出,序列化后的对象会附带所属类型,这个类名保证此对象在执行类的方法(也是本身所能执行的方法)时, 可以正确地找到方法所在的代码空间(即对象所拥有的方法存储在类里)。另外,当一个对象的实例变量引用其余对象时,序列化对象 也会对引用对象进行序列化 由此能够分析两者的关系 : 类是定义一系列属性和操做的模板,而对象则是把属性进行具体化,而后交给类处理 对象就是数据,对象自己包含方法。可是对象有一个”指针“指向一个类,这个类里能够有方法。 方法描述不一样属性致使的不一样表现 类和对象是不可分割的,有对象就一定有一个类与其对应,不然这个对象也就成了没有亲人的孩子(但有一个特殊的状况,就是 由标量进行强制类型转换的object,没有一个类与它对应。此时,PHP中一个称为”孤儿“的stdClass类就会收留这个对象) 能够看出,在面向对象层面,js和php区别仍是很大的。 */ /*魔术方法*/ /* * 魔术方法是以两个下划线开头,具备特殊做用的一些方法,能够看做是PHP的语法糖 * 语法糖是指那些没有给计算机添加新功能,而对人类来讲更甜蜜的语法 * Family类的__construct方法就是一个标准的魔术方法。这个魔术方法又称构造方法。具备构造方法的类会每次建立对象时 * 先调用此方法,因此很是适合在使用对象以前作一些初始化工做,如:给属性赋值,链接数据库等 * 有构造方法就有析构方法,即destruct方法,这个方法会在某个对象的因此引用都被删除,或者当对象被显式销毁时执行。 * 这两个方法是最多见也是最有用的魔术方法 */ /*魔术方法之set 和 get*/ class Account{ private $user = 1; private $pwd = 2; public function __get($name){ echo '请求'.$name; } public function __set($name,$val){ echo "请求设置".$name."为".$val; } public function __call($name ,$arguments){ // $name : 要调用的方法名称 // $arguments : 数组,包含着要传递给方法的参数 var_dump($name); var_dump($arguments); } public static function __callStatic($name ,$arguments){ var_dump($name); var_dump($arguments); } public function __toString() { return '任意字符串'; } } $a = new Account(); $a->user; // 若是没有 __get 魔术方法则会报错,大体意思是不能访问对象的私有属性 // 请求user $a->name = '123'; // 由于对象没有name属性,因此会触发 __set 魔术方法 // 请求设置name为123 /* * 能够直观的看到,若类中定义了set 和 get这一对魔术方法,那么当给对象属性赋值或取值时,即便 * 这个属性不存在,也不会报错,必定程度上加强了程序的健壮性 */ // 那么,若是防止调用一个不可访问的方法(如未定义,或者不可见)时,call()会被调用。 $a->demo('1','2'); // "demo" // array(2) { [0]=> string(1) "1" [1]=> string(1) "2" } // 当调用的静态方法不存在或权限不足时,callStatic() 会被调用 Account::demo(); // "demo" // array(0) { } // 固然,使用魔术方法"防止调用不存在的方法而报错",并非魔术方法的本意。实际上,魔术方法使方法的动态建立变为可能。 // 这在MVC等框架设计中是颇有用的语法。能够经过一段代码使用callStatic这一魔术方法进行方法的动态建立和延迟绑定 // toString方法 echo $a; //任意字符串 // 好比打印一个对象时,看看这个对象都有哪些属性,其值是什么,若是定义了toString方法,就能在测试时,echo打印对象体 // 对象会自动调用它所属类定义的toString方法,格式化输出这个对象所包含的数据。若是没有这个方法,那么echo一个对对象将报错
<?php /** * Created by PhpStorm. * User: chenglin * Date: 2019/8/12 * Time: 7:08 */ /*oop高级*/ class Person{ public $name = 'tom'; public $gender; public $money = 1000; public function __construct(){ echo '这里是父类'; } public function say(){ var_dump( $this->name); } } class Family extends Person{ public $name; public $gender; public $money = 100000; public function __construct(){ parent::__construct(); echo "这里是子类"; } public function say(){ parent::say(); } } $poor = new Family(); $poor->say(); // 这里是父类 // 这里是子类 // NULL /* * 从上面的代码中能够了解继承的实现。在继承中,用parent指代父类,用self指代自身。 * 使用"::"操做符(范围解析操做符)调用父类的方法。"::"操做符还能够做为类常量和静态方法的调用,不要把这两种应用混淆。 * 既然提到静态,就再强调一点。若是声明类成员或方法为static,就能够不实例化类而直接访问 */ /*接口*/ /* * 这里,首先强调一个概念,面向接口编程并非一种新的编程范式。本章开头提到的三大范式中并无提到面向接口。其实, * 这里是狭义的接口,即 interface 关键字。广义的接口能够是任何一个对外提供服务的出口,好比提供数据传输的usb接口, * 、淘宝网对其余网站开放的支付宝接口。 * 接口定义一套规范,描述一个"物"的功能,要求若是现实中的"物"想成为可用,就必须实现这些基本功能。接口这样描述本身: * "对于实现个人因此类,看起来都应该向我如今这个样子" * 在程序中,接口的方法必须被所有实现,不然会报fetal错误 */ interface mobile{ public function run(); // 驱动方法 } class plain implements mobile{ public function run() { // TODO: Implement run() method. echo "我是飞机"; } public function fly(){ echo "飞行"; } } (new plain())->fly(); // 飞行 // 思考: 接口自己并不提供实现,只要提供一个规范。 // php中,接口的语义是有限的,使用接口的地方并很少,php中接口能够淡化为设计文档,起到一个团队基本契约的做用 // 因为php是弱类型,且强调灵活,因此并不推荐大规模使用接口,而仅在部分"内核"代码中使用接口。从语义上考虑, // 能够更多地使用抽象类 //抽象类 abstract class Fruits{ // 水果名称 protected $name; // 抽象方法 abstract public function eat(); // 尽管不能实例化抽象类,但仍然能够有构造方法 public function __construct(){ echo "抽象构造器,实例化时自动调用" ; } } class Apple extends Fruits{ protected $name = "苹果"; public function eat(){ echo $this->name . "能够直接生吃"; } // 子类构造方法 public function __construct() { echo parent::__construct(); } } $apple = new Apple(); echo $apple->eat(); // 抽象构造器,实例化时自动调用 // 苹果能够直接生吃 // 抽象类提供了具体实现的标准,而接口则是纯粹的模板 /*反射*/ /* * 面向对象编程中对象被赋予了自省的能力,而这个自省的过程就是反射。 * 反射,直观理解就是根据到达地找到出发地和来源。比方说:我给你一个光秃秃的对象,我能够 * 仅仅经过这个对象就能直到它所属的类,拥有哪些方法 */ // 反射API $reflect = new ReflectionObject($apple); // 获取对象属性列表 $props = $reflect->getProperties(); foreach ($props as $prop){ var_dump($prop->getName()); } // string(4) "name" // 获取对象的方法列表 $m = $reflect->getMethods(); foreach ($m as $prop){ var_dump($prop->getName()); } // string(3) "eat" // string(11) "__construct" // 也能够不用反射API,使用class函数,返回对象属性的关联数组以及更多信息 var_dump(get_object_vars($apple)); // 返回对象属性的关联数组 // array(0) { } var_dump(get_class_vars(get_class($apple))); // 类属性 // array(0) { } var_dump(get_class_methods(get_class($apple))); // 返回由类的方法名组成的数组 // array(2) { [0]=> string(3) "eat" [1]=> string(11) "__construct" } // 在此。利用强大的反射API功能范元这个类的原型,包括方法的访问权限: $obj = new ReflectionClass('Apple'); // 获取类型 $className = $obj -> getName(); // 初始化方法和成量数组 $methods = $properties = []; foreach ($obj->getProperties() as $v){ $properties[$v->getName()] = $v; } foreach ($obj->getMethods() as $v){ $methods[$v->getName()] = $v; } echo "<br />class {$className}<br />{<br />"; is_array($properties) && ksort($properties); // 数组排序 // 遍历出类的属性 foreach ($properties as $k => $v){ echo "\t"; echo $v->isPublic() ? 'public' : '',$v->isPrivate() ? 'private' : '',$v->isProtected() ? 'protected' : '', $v->isStatic() ? 'static' : ''; echo "\t{$k}"; } // 遍历出类的方法 is_array($methods) && ksort($methods); // 数组排序 foreach ($methods as $k => $v){ echo "<br />function $k(){}"; } echo "<br / >}"; /* class Apple{ protected name function __construct(){} function eat(){} } */ /* * 反射的做用: 用于文档生成。所以能够用它对文件里的类进行扫描,逐个生成描述文档 *