牛骨文教育服务平台(让学习变的简单)
博文笔记

PHP面向对象基础

创建时间:2016-07-06 投稿人: 浏览次数:386

概念

一种程序设计范型,同时也是一种程序开发方法。将对象作为程序基本单元,将程序和数据封装其中,提供软件的重用性、灵活性和可扩展性。属性+方法;

对象的本

php使用一种zend_object_value结构体来存储对象。
typedef struct _zend_object{
        zend_class_entry *ce;//这里是类入口
        HashTable *properties;//属性组成的hashtable
        HashTable *guards;//protected from __get
    }zend_object;

类声明

一个文件只保存一个类,文件名包含类名,文件:类名.class.php或者类名.php

魔术方法的应用

__开头、具有特殊作用的一些方法,PHP的语法糖。

__set():设置对象的不存在的属性,自动调用__set();
__get():当获取对象中不存在的属性,会自动调用__get();
当给对象属性赋值或者取值的时候,属性不存在,也不会报错,一定程度上增强了程序的健壮性。

__call($name, $arguments):当调用对象中不存在的方法,自动调用__call()这个方法;$name:表示的是调用的方法名称。$arguments参数是一个数组包含要传递给方法的参数。
__callStatic():
MVC中如果控制器用了不存在的方法,那么只要定义__call()魔术方法,就能友好的处理这种情况;

__toString()方法:
当打印echo出一个对象的时候,直接回调用__toString()这个方法,也就是打印出序列化的对象。
可以对__toString()进行自定义;
public function __toString(){
    return "当前对象的用户名,密码是:";
}
echo本来可以打印一个对象的只是php对其做了限制,只有实现__toString后才允许使用。

继承和多态

继承和多态,对类的复用实现。一个是类级别的复用,一个是方法级别的复用。
类的组合与继承
组合:在一个类中,某个属性去实例化其他类,这个复用方式就是组合。
继承:子类,父类的关系;
parent:表示父类;self:表示自身。使用::来调用父类的方法;
组合偏重整体与局部的关系,而继承偏重父与子的关系;

耦合是一个软件结构内不同模块之间互联程度的度量,不同模块之间的依赖关系。
继承存在问题:
    1、继承破坏封装性。(有些对象不需要用到所有父类的方法)
    2、继承是紧耦合的。
    3、继承扩展复杂;
    4、不恰当使用继承可能违反现实世界中的逻辑。
慎重使用继承:
    专门用于被继承的类,继承树的抽象层应该比较稳定,一般不要多于三层;
    对于不是专门用于被继承的类,禁止其被继承,使用final修饰符。
    优先考虑组合关系提高代码的可重用性。
    子类是扩展而不是覆盖或者使父类的功能失效。
    底层代码多用组合,顶层/业务层代码多用继承。
各种语言中的多态
多态:同一类的对象收到相同消息时,会得到不同的结果,而这个消息是不可预测的。
多态:多种状态,多种结果。
PHP作为脚本语言,本身就是多态的。相同参数类型,得到不同的结果。调用相同的参数,返回不同结果。
<?php
class employee{
   protected function working(){
       echo "本方法需要重载";
   }
}
class teacher extends employee{
    public function working() {
        echo "教书";
    }
}
class coder extends employee{
    public function working() {
        echo "敲代码";
    }
}

function dopring($obj)
{
    if(get_class($obj) == "employee") {
        echo "error";
    }else{
        $obj->working();
    }
}
dopring(new teacher());
dopring(new coder());
dopring(new employee());
面向接口编程
接口的作用:提供一套规范,所有用我这个接口的类就必须实现接口声明的方法;
接口为抽象而生。
<?php
interface mobile{
    public function run();
}
class plain implements mobile{
    public function run(){
       echo "我是飞机"; 
    }
    public function fly() {
        echo "我能飞行";
    }
}
class car implements mobile{
    public function run()
    {
        echo "我是汽车";
    }
}

php5面向对象的特性做了很多增强,SPL标准PHP库的尝试。SPL中实现一些接口。接口是多重继承的一种变相实现。

面向对象的设计准则

设计五大原则

单一职责原则
这是一个最简单、最容易理解却也是不容易做到的一个设计原则
避免相同的职责分散到不同类中,另一个需要避免一个类承担太多职责
遵守SRP:(单一职责体现)
    1、可以减少类之间的耦合
    2、提高类的复用性
实例:
框架中的ORM模型编写中的数据库连接操作,工厂类负责抽象出来,不实现具体操作。
具体的操作在不同数据库类中进行实现,根据传入不同参数来判定不同的数据库,并调用相关实现类。
命令请求者和命令实现者职责分离。
《敏捷软件开发-原则方法与实践》
接口隔离原则
设计应用程序如果一个模块包含多个子模块,需要小心处理模块做抽象
接口隔离:ISP interface segregation principle
    客户端不应该被强迫实现一些他们不会使用的接口,应该把胖接口中的方法分组,然后用多个接口代替它。
    每个接口服务于一个子模块。
观点:
    1、一个类对另外一个类依赖性应该建立在最小接口上。
    2、客户端程序不应该依赖它不需要的接口方法
接口污染:
    为接口添加不必要的职责,如果接口中增加一个新功能目的减少接口实现类数量会到接口不断被污染。
    为系统带来维护和重用性差等方面问题。
    接口隔离:定制化服务设计原则。(按需服务,实现多接口)接口既要拆但是也不能拆了太细。
    高内聚:接口应该具备一些基本的功能,能独自完成一个基本任务。
开放-封闭原则
开放:模块的行为必须是开放的、支持扩展的,而不是僵化的。
一个模块在扩展性方面应该是开放的而在更改性方面应该是封闭的。
实例:
    对外提供支付接口,必须保证接口的稳定性,同时又要使得接口是可扩展的。
    思考对接口进行抽象:定义一个工厂类:负责实例化具体类,调用相关方法。
<?php
namespace apppaymodel;
/**
 * @class 工厂-对接封装了各个通道支付
 * @param ins_type:要实例化通道的类文件
 * @param data :支付接口参数
 */

class PayApi{

    private $pay_ins = null;//支付通道实例

    /**
     *@function 初始化
     */
    private function factory($pay_ins_type = "") {

        if($this->pay_ins !== null) {//如果没有实例化
            return false;
        }
        $now_dir = rtrim(str_replace("\", "/", dirname(__FILE__)), "/");
        if(!is_file($now_dir."/".$pay_ins_type.".php")) {
            return false;
        }
        $class = "\app\pay\model\".$pay_ins_type;
        $this->pay_ins = new $class();
        return true;
    }

    /**
     * @function 扫码支付
     *
     */
    public function scan_code_pay($data = array(), $ins_type = "") {
        if(!$this->factory($ins_type)) return return_error_mess("make_ins_fail");
        return $this->pay_ins->scan_code_pay($data);//扫码支付
    }
}
具体实现方法可以放在具体的通道类:后续有新增通道只是需要实现其工厂类中的方法即可实现扩展。
class WeiZone {
    private $fileCharset = "UTF8";
    private $pay_type    = array("2");
    private $url = "http://notify_url";//微众通知接口

    /**
     * @function 扫码支付-具体实现类
     *
     */
    public function scan_code_pay($request = array()) {
        if($request["pay_ver"] == "001") {
            if(empty($request["chanel_info"])) return return_error_mess("chanel_info_null");
            $chanel_info = json_decode($request["chanel_info"], true);
            if(empty($chanel_info)) return  return_error_mess("chanel_info_null");

            ...................

        }else{
            return return_error_mess("pay_ver_deny");
        }
    }
}
替换原则
由于面向对象中的继承在具体编程中过于简单,造成喜多系统设计滥用继承或者错误了进行继承等现象。
替换原则:LSP
    子类必须能替换掉它们的父类,并出现在父类能够出现的地方,合理进行继承与派生,合理重用代码。
PHP对于LSP的支持并不好。
<?php
abstract class Cache{
    public abstract function set($key, $value, $expire=60);
    public abstract function get($key);
    public abstract function del($key);
    public abstract function delAll($key); 
    public abstract function has($key); 
}
依赖倒置原则
上层模块不应该依赖于下层模块,它们共同依赖于一个抽象(父类不能依赖于子类,它们都要依赖抽象类)

PHP并非一门好的面向对象语言,无法做到完全面向对象也无法优雅实现面向对象。一般大多使用精简的MVC理论,比较少用设计模式。以类加代码模块的方式进行代码组织。zend framework纯面向对象的比较少。

声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。