一次性搞懂 PHP 中面向对象的所有知识点。
发布时间:2024-03-07

    OOP是什么?

    OOP是面向对象编程,面向对象编程是一种计算机编程架构。

    OOP的基本原则是计算机程序是由单个能起到子程序作用的单元或对象组合而成。

    基本概念:

    类:定义了事务的抽象特点。包含了数据的形式以及数据的操作。class 定义类。
    对象:类的实例。new 运算符类实例化为对象。
    成员变量:定义在类内的变量。类实例化为对象后,该变量称为对象的属性。
    成员函数:定义在类内的方法。
    重载:函数或者方法有同样的名称,但是参数列表不相同的情形。
    什么是构造函数,什么是析构函数,作用是什么?

    构造函数

    构造函数(方法)是对象创建完成后第一个被对象自动调用的方法。

    它存在于每个声明的类中,是一个特殊的成员方法。

    作用是执行一些初始化的任务。 PHP中使用 __construct() 声明构造方法,并且只能声明一个。

    析构函数

    析构函数(方法)作用和构造方法正好相反,是对象被销毁之前最后一个被对象自动调用的方法。

    是PHP5中添加的内容,作用是用于实现在销毁一个对象之前执行一些特定的操作;

    诸如关闭文件和释放内存等。 使用__destruct()声明析构函数。

    什么是魔术方法?

    魔术方法时系统提供的,我们直接使用即可。
    所有的魔术方法都是以 __ (两个下划线)开头的。
    魔术方法是在满足某个条件时,由系统自动调用的
    魔术方法有哪些?

    __construct() 构造函数
    __destruct() 析构函数
    __sleep() 串行化/序列化的时候用
    __wakeup() 反串行化/反序列化的时候用
    __toString() 将一个对象当做字符串来输出时调用
    __clone() 克隆对象时被调用
    __autoload() 实例化一个对象时,如果对应的类不存在,则该方法被调用
    __call() 调用方法,若方法存在、则直接调用;若不存在,则调用__call() 函数
    __set() 设置对象属性,若属性存在、则直接赋值;若不存在、则调用__set()函数
    __get() 获取对象属性,若属性存在、则直接返回;若不存在、则调用__get()函数
    __iseet() 检测一个对象的属性是否存在时被调

    __unset() 清除一个对象的属性时被调用


    OOP的三大特点?

    封装性

    就是将一个类的使用和实现分开, 只保留部分接口和方法与外部联系,或者说只公开了一些供开发人员使用的方法。于是开发人员只需要关注这个类如何使用,而不用去关心其具体的实现过程,这样就能实现MVC分工合作,也能有效避免程序间相互依赖,实现代码模块间松藕合。

    继承性

    就是子类自动继承其父级类中的属性和方法,并可以添加新的属性和方法或者对部分属性和方法进行重写。继承增加了代码的可重用性。PHP只支持单继承,也就是说一个子类只能有一个父类。

    多态性

    子类继承了来自父级类中的属性和方法,并对其中部分方法进行重写。于是多个子类中虽然都具有同一个方法,但是这些子类实例化的对象调用这些相同的方法后却可以获得完全不同的结果,这种技术就是多态性。多态性增强了软件的灵活性。

    OOP的优点有哪些?

    易维护

    采用面向对象思想设计的结构,可读性高,由于继承的存在,即使改变需求,那么维护也只是在局部模块,所以维护起来是非常方便和较低成本的。

    质量高

    在设计时,可重用现有的,在以前的项目的领域中已被测试过的类使系统满足业务需求并具有较高的质量。

    效率高

    在软件开发时,根据设计的需要对现实世界的事物进行抽象,产生类。使用这样的方法解决问题,接近于日常生活和自然的思考方式,势必提高软件开发的效率和质量。

    易扩展

    由于继承、封装、多态的特性,自然设计出高内聚、低耦合的系统结构,使得系统更灵活、更容易扩展,而且成本较低。

    方法重写

    // 如果从父类继承的方法不能满足子类的需求,可以对其进行改写;
    // 这个过程叫方法的覆盖(override),也称为方法的重写。
    // 实例中重写了 getUrl 方法:
    
    /***** 原来的 ****/
    class p {
      var $url;
      var $title
      
      function getUrl()
      {
        echo $this->url;
      }
    }
    
    
    /***** 继承后重写 ****/
    class s extends p {
      var $url;
      var $title
      
      function getUrl()
      {
        echo $this->url.'/'.$this->title;
      }
    }
    

    面向对象中 public、protected、private 三种访问控制模式的区别是:

    public(公有):公有的类成员可以在任何地方被访问。
    protected(受保护):受保护的类成员则可以被其自身以及其子类和父类访问。
    private(私有):私有的类成员则只能被其定义所在的类访问。
    接口 和 抽象类 分别是什么?有哪些区别?

    抽象类

    抽象类通过 abstract 关键字来声明的。

    抽象类不能被实例化,只能使用 extends 继承抽象类。

    抽象类中至少包含一个抽象方法。

    抽象类中的抽象方法只是声明了其调用方式或参数,所有的抽象方法都是空的。

    抽象类中的抽象方法天生就是要被子类重写的。

    抽象类继承的时候,子类必须实现父类中的所有抽象方法。

    子类中的方法的访问控制必须和父类中的一样或者更为宽松;

    子类中定义了一个可选参数,而父类抽象方法的声明里没有,则也是可以正常运行的。

    接口

    接口通过 interface 关键字来声明的。

    接口不能被实例化,只能使用 implements 实现接口。

    接口中的成员常量和方法都是 public 的,这是接口的特性。

    接口中的方法也只是声明了其调用方式或参数,所有的方法都是空的。

    接口中的方法天生就是要被子类实现的。

    接口实现的时候,类中必须实现接口中定义的所有方法,否则会报一个致命错误。

    类可以实现多个接口,用逗号来分隔多个接口的名称。

    区别

    抽象类和接口实现的功能十分相似,最大的不同是接口能实现多继承。

    Static 关键字

    声明类属性和方法为静态的,可以不用实例化类而直接访问。
    静态属性不能通过一个类已实例化的对象类访问,但是静态方法可以访问。
    静态方法不需要通过对象即可调用。所以 $this 在静态方法中不可以使用。
    Final 关键字

    PHP5中新增的。
    如果父类中的方法被声明为final,则子类无法覆盖该方法。
    如果一个类被声明为 final,则不能被继承。

    多继承

    trait test_a
    {
        function fun_a()
        {
            echo "a";
        }
    }
    
    
    trait test_b
    {
        function fun_b()
        {
            echo "b";
        }
    }
    
    
    class test
    {
        use test_a test_b;
        function fun_a()
        {
            echo 'ca';
        }
    }
    
    
    $t = new test;
    $t->fun_a();
    $t->fun_b();


    序列化/反序列化

    序列化:把本来不能直接存储的数据转换成可存储的数据,并且不会丢掉数据格式

    serialize();

    反序列化:把序列化后的数据,转换成我们需要的格式

    unserialize();

    案例

    // 数组
    $arr = array(
        'name'=>'mike' 
        'birth'=>'0101' 
        'sex'=>1
    );
    
    
    //序列化
    $serialized_data = serialize($arr);
    echo $serialized_data;
    // 得到
    // a:3:{s:4:"name";s:4:"mike";s:5:"birth";s:4:"0101";s:3:"sex";i:1;}
    
    
    //反序列化
    $res = unserialize($serialized_data);
    var_dump($res);
    //得到
    /*
    array(3) {
        ["name"]=>
        string(4) "mike"
        ["birth"]=>
        string(4) "0101"
        ["sex"]=>
        int(1)
    }
    */