1.面向对象类是属性和方法的集合, PHP的对象是用数组来模拟的。序列化对象后,存储的只是对象的属性。类是由属性和方法组成的,而对象则是属性的集合。由同一个类生成的不同对象,拥有不同的属性,但共享了类的代码空间中方法区域的代码。在PHP5中,对象在底层的实现是采用 '属性数组 + 方法数组' 来实现的。对象的组成 :1.属性数组2.类指针1.类属性2.静态属性3.类常量4.标准方法5.魔术方法6.自定义方法列表对象与数组的区别在于:对象还有个指针,指向了它所属的类。序列化后的对象会附带所属的类名,这个类名保证此对象能够在执行类的方法时,能够正确的找到方法所在的代码空间(即对象所拥有的方法存储在类里面)。另外,当一个对象的实例变量引用其他对象时,序列化该对象时也会对引用对象进行序列化。1.类是定义一些列属性和操作的模板,而对象则把属性进行具体化,然后交给类处理。2.对象就是数据,对象本身不包含方法。但是对象有一个'指针'指向一个类,这个类里可以有方法。3.方法描述不同属性所导致的不同表现。4.类和对象是不可分割的,有对象就必定有一个类和其对应。耦合是一个软件结构内不同模块之间互连程度的度量,也就是不同模块之间的依赖关系。解耦是要接触模块与模块之间的依赖。继承与组合更倾向使用组合,为什么呢?1.继承破坏封装性鸟类为父类,但其子类鸭子等不需要飞翔这个方法,但却可以无区别的使用。2.继承是耦合的继承使得子类和父类捆绑在一起,组合仅通过唯一接口和外部进行通信。3.继承扩展复杂随着继承层数的增加和子类的增加,将涉及大量方法重写。使用组合,可以根据类型约束,实现动态组合,减少代码。4.不恰当的使用继承可能违反现实世界的逻辑组合的缺点:在创建组合对象的时候,组合需要一一创建局部对象。组合比继承增加了代码量。继承最大的优点是扩展简单。如何使用继承?1.精心设计专门用于被继承的类,继承树的抽象层应该比较稳定,一般不要多于3层。2.对于不是专门用于被继承的类,禁止其被继承,也就是使用 final 修饰符。使用 final 修饰符即可防止重要方法被非法覆盖,又能给编译器寻找优化的机会。1.优先考虑组合关系提高代码的可重用性2.子类是一个特殊的类型,而不只是父类的一个角色3.子类扩展,而不是覆盖或者使用父类的功能失效4.底层代码多用组合,顶层/业务层代码多用继承。底层用组合可以提高效率,避免对象臃肿。顶层代码用继承可以提高灵活性,让业务更方便。如果既要组合的灵活,又要继承的代码简洁?使用多重继承。一个类可以同时继承多个父类,组合两个父类的功能。PHP 5.4 引入的 traits 可以方便我们实现对象的扩展,是除 extend, implements 外的另外一种扩展对象的方式。2.多态同一类的对象收到相同消息时,会得到不同的结果。多态性是一种通过多种状态或阶段描述相同对象的编程方式。它真正的意义在于:实际开发中,只要关系一个接口或基类的编程,而不必关心一个对象所属的具体类。PHP 作为一门脚本语言,本身就是多态的。C++ 中的多态,定义一个父类,然后定义一个子类,这个子类继承父类的一些方法并且有自己的方法。通过 father *pf = new son; 语句创建一个派生类(子类)对象,并且把该派生类对象赋值给基类(父类)指针,然后用该指针访问父类中的 eat 和 run 方法。由于父类中的 run 方法加了 virtual 关键字,表示该函数有多种状态,可能被多个对象所拥有。也就是说,多个对象在调用同一名字的函数时会产生不同的效果。和 PHP 有什么不同呢?C++ 的这个例子所创建的对象是一个指向父类的子对象,还可以创建更多的派生类,然后上转型为父类对象。这些对象,都是同一类对象,但是在运行时,却都能调用到派生类同名函数。而PHP中的例子则是不同类的对象调用。由于PHP是弱类型,并且也没有对象转型机制,所有不能像C++那样实现 father *pf = new son; 把派生类对象赋给基类对象,然后在调用的时候动态的改变其指向。在PHP中,对象是确定的,是不同类的对象。所以,从这个角度看,不是真正的多态。区别多态的关键在于看对象是否属于同一类型。如果把它们看做同一种类型,调用了相同函数,返回了不同结果,那么它就是多态。否则,不是称其为多态。1.多态指同一类对象在运行时的具体化2.PHP语言是弱类型,实现多态更简单3.类型转换不是多态4.PHP中父类和子类看做 '继父'和'继子' 关系,它们存在继承关系,不存在血缘关系。因此子类无法向上转型为父类,从而失去多态的最典型特征。5.多态的本质就是 if...else,只不过实现的层级不同。3.面向接口编程接口定义一套规范,描述一个'物'的功能。采用一个特定接口的所有代码都知道对于那个接口会调用什么方法。这便是接口的全部含义。接口通常作为类与类之间的一个'协议'。接口是抽象类的变体,接口中所有的方法都是抽象的,没有一个程序体。接口除了可以包含方法外,还可以包含常量。接口为抽象而生,接口是一种契约。大型项目中,核心开发人员和技术经理编写核心的流程和代码,以接口形式给出。而基础开发人员,指针对这些接口,填充代码,如数据库操作等。这样,核心人员把更多精力投入到了技术公关和业务逻辑中。前端只针对接口编程,只管在 Action 层调用 Service,不管实现细节。而后端则负责Dao和 Service层接口的实现。为什么一个类实现了 Iterator 迭代器,其对象就可以被用作 foreach 呢。原因是,在对 PHP 实例对象使用 foreach 时,会检查这个实例有没有实现Iterator 接口,如果实现了,就会通过内置方法或者使用实现类中的方法模拟 foreach语句。这和 __toString() 很像,事实上,__toString()方法就是接口的一种变相实现。接口是对多重继承的一种变相实现,trait 可以被视为一种加强型接口。trait 和接口很像,不同的是 trait 是可以导入包含代码的接口。4.反射面向对象编程中对象被赋予了自身的能力,而这个自身的过程就是反射。反射,直观理解就是根据到达地找到出发地和来源。反射指在 PHP 运行状态中,扩展分析 PHP 程序,到处或提取关于类,方法,属性,参数等详细信息,包括注释。这种动态获取信息以及动态调用对象方法的功能被称为反射 API。反射的作用:反射可以用于生成文档。因此它可以对文件里的类进行扫描,逐个生成描述文档。既然反射可以探知类的内部结构,那么是不是可以用它做 hook 实现插件功能?或者是做动态代理呢?<?phpclass mysql{public function connect($db){echo '连接到数据库 db';}}class sqlproxy{private $target;public function __construct($tar){$this->target[] = new $tar();}public function __call($name, $arguments){foreach ($this->target as $obj) {$r = new ReflectionClass($obj);if ($method = $r->getMethod($name)) {if ($method->isPublic() && !$method->isAbstract()) {echo '方法前拦截记录';$method->invoke($obj, $args);echo '方法后拦截';}}}}}$obj = new sqlproxy('mysql');$obj->connect('member');这里真正操作的类是 mysql,但是 sqlproxy 类实现了根据动态传入参数,代替实际的类运行,并且在方法前后进行拦截,并且动态的改变了方法和属性。这就是简单的动态代理。反射的消耗很大。反射可以保持代码的优雅和简洁,但反射也会破坏类的封装性,因为暴露了方法和属性。5.错误和异常PHP 里的异常,是程序运行中不符合预期的情况以及正常流程不同的状况。异常和错误是2个不同的概念。PHP 只有手动抛出异常后才能捕获异常。下面3种场景用到异常:1.对程序的悲观预测2.程序的需要和对业务的关注3.语言级别的健壮性要求PHP 的错误级别:1.deprecated2.notice3.warning4.fetal5.parse errorset_error_handler();trigger_error();
1.1 对象的本
如果觉得《1.PHP核心技术与最佳实践 --- 面向对象思想的核心概念》对你有帮助,请点赞、收藏,并留下你的观点哦!