PHP面向对象之朝花夕拾

时间:2021-10-11 21:18:54

虽然平时都在用面向对象的思维编程。但是都是基于框架,很多技术细节一段时间不用就会逐渐模糊。
拾遗部分:
面向对象的三大特称:
继承
多态
封装。

构造方法。__construct()  构造方法。再new的时候调用。
析构方法. __destruct()   析构方法。分崩离析的意思。再对象销毁的时候调用。注意,虽然可以销毁对象,但是内存并不会因此而清除。php的销毁只是将内存地址与内容的关系绑定解除。而内存释放则要判断内存
里面的内容是不是孤立的,再也没有其他的地方引用。

对象的成员属性非常好用,用的好可以优化代码。
对象的成员属性有以下的几个要求:
对象的成员属性不能是变量,不能有表达式。
对象的成员属性可以使常量,可以有默认值。
默认值的类型可以使任意类型,包括对象。
访问的时候用$this -> varible 来访问成员属性。

对成员属性的保护:
private 私有属性
protected 受保护的属性。

如果再外部想要访问私有属性,可以通过。__get($key) 的方法来访问。在__get的内部可以通过if else来进行判断。判断那些私有属性可以访问,那些私有属性不能访问。
当然也能通过__set($key, $val)的方式来设置本来不能设置的私有属性。
__get($key)       访问本权限访问的属性的时候会自动调用
__set($key,$val)  在本没有权限对属性赋值的时候会自动调用
__isset($key)     在本没有权限使用isset函数判断属性的时候 自动调用
__unset($key)     在本没有权限使用unset函数销毁属性的时候自动调用

通过extends继承。子类可以继承父类的所有方法和成员属性,但是是否能够访问还要看父类方法和属性前的修饰词。

封装的三个范围:
            针对被封装的东西
            外部(任何类的定义花括号之外)
            自己(定义这个类本身的花括号)
            子类(定义子类的花括号)

三个关键字
            public
            private
            protected

public 外部  子类  自己都是可以访问的
        protected  子类和自己是可以访问的  外部不能访问
        private 只有自己可以访问  外部和子类是无法访问的

public      protected       private
        外部      Y             N              N
        子类      Y             Y              N
        自己      Y             Y              Y
        
::    范围操作符  前面是类  后面是方法
                  A::方法名
                  parent::方法名
                  self::方法名
                  
面向对象的继承
            目标:
                没有重复代码  便于维护

继承的特性
                php中只能有一个父类(只能有一个爹)
                php中的类可以被多个继承(一个爹可以有多个儿子)
                php中可以多层继承
                    C继承B  B继承A   那么在C里面就有了 A B C里面所有的内容

属性的继承(重载  重构)
                子类中出现与父类中同名的属性,那么会覆盖父类中属性的值
                如果子类中只定义不赋值,那么值为null
                如果是私有的,那么最终会产生多个同名属性,隶属于不同的类
                权限只能扩大不能缩小(大小指的是有效范围)
                    对于public 而言     子类只能是 public
                    对于protected 而言  子类可以是 public protected
                    对于private 而言    子类可以是 public protected private
                    
方法的继承
                子类中出现与父类中同名的方法,那么会覆盖父类中的方法
                普通方法
                重写方法的时候  参数个数应该和父类中保持一致
                形参是否有默认值得保持一致
                默认值是什么可以随意
                魔术方法,例如构造方法
                    无需保证参数个数统一
                如果重写构造方法,那么在第一行调用一次父类的构造方法  parent::__construct();
                
 final
            可以修饰类和方法
            被修饰的类不能被继承
            被修饰的方法不能被重写

static
            不能修饰类,只能修饰属性和方法
            被修饰的属性和方法需要使用范围操作符来访问  属性: A::$name
            在静态的方法中不能出现非静态的内容
            
const
            可以在类里面定义常量
            值不能有表达式
            类里面的常量  需要使用范围操作符来访问
define
    不能在类里面定义常量
    值可以有表达式
    
instanceof  操作符    &&  and
            判断前面的对象是不是后面类的实例
            如果存在继承关系  那么用于判断父类(祖宗类)  也范围true
            
            
            
单态设计模式:
 /*
        单态设计模式:

始终只能得到一个唯一的对象的模式

步骤:
            1.我们要阻止在外面 new        封装构造方法
            2.我们可以提供一个方法让外面调用     在没有对象的时候调用方法  ----->  static
            3.静态方法可以多次调用   我们需要判断是否要new   我们需要一个判断条件 ---> 属性
            4.在静态的方法里面不能出现 $this  所以 这个判断依据 我们也用static修饰
            5.在获得连接的方法里面选择性的 new  最终得到唯一的对象
    */

class MySQL{
        static private $link = null;

private function __construct(){}

static public function getConnect(){
            if(is_null(self::$link)){
                self::$link =  new MySQL;
            }

return self::$link;
        }
    }

$db1 = MySQL::getConnect();
    $db2 = MySQL::getConnect();

if($db1 === $db2){
        echo 'Y';
    }else{
        echo 'N';
    }
    
当调用一个不存在的方法的时候对自动调用:__call($name, $list); $name是方法名。$list是该方法的参数。是要给数组。
访问一个不存在的静态方法的时候自动调用  参数与 __call一样,这个魔术方法本身  也必须是一个静态方法
//使用 clone 关键字 可以克隆一个对象  是一个新对象__clone()

class A{
        public $name;
        public $age;
        public $size = '36D';

//使用serialize 将一个对象串行化为字符串的时候自动调用
        public function __sleep(){
            //允许被传递的属性列表
            return array('name','age','test','size');
        }

//反串行化得到对象的时候自动调用
        public function __wakeup(){
            echo '我新生了。。。';
        }

// 使用 new关键字 得到对象的时候自动调用
        public function __construct(){
            echo '我来了。。。<br>';
        }
    }

$p = new A;
    $p->name = 'jack';
    $p->age = 18;
    $p->size = '40G';

$obj = serialize($p);

echo $obj;

//会得到一个新的对象
    //反串行化的时候会自动调用 __wakeup
    $newobj = unserialize($obj);

echo "<pre>";
        print_r($newobj);
    echo "</pre>";

echo '<hr>';

if($p === $newobj){
        echo 'Y';
    }else{
        echo 'N';
    }
    
/*
        class  new  public  protected  private  static  final  const   instanceof
        self   parent   clone   $this   extends

#####################################################################

class

[修饰符] class 类名{
            [成员属性]
                可以有默认值
                默认值不能是变量
                默认值不能有表达式
                默认值可以是常量
            [成员方法]
                与以往的函数一致

除了以上两种不能再出现其他内容
        }

new
        实例化对象  每次new都会得到一个新的对象

封装
                    public    protected    private
        自己          Y           Y           Y
        有一腿        Y           Y           N
        外部          Y           N           N

static
            可以修饰属性和方法  不能修饰类
            被修饰的属性和方法需要使用范围操作符来访问
            静态方法里面不能出现非静态的内容($this)

final
            可以修饰类和方法  不能修饰属性
            被修饰的类不允许被继承(最终版本)
            被修饰的方法不能被重写(最终版本的方法)

const
            可以在类里面定义常量
            值不能出现表达式
            也可以用于在类外面定义常量(PHP版本 5.3+)
        define
            不能在类里面定义常量
            值可以有表达式

instanceof   二元运算符   
            if($a instanceof A)   判断$a 是不是 A类的实例   如果类是对象的祖宗也是可以的

$this
            伪变量(在方法里面访问自己的方法或属性)
            代表的是对象  表示的是自己
        ----------
        以下两个都表示的是类
        self
            表示的是自己这个类
        parent
            表示的是父类

->
            成员访问符      前面是对象   后面数对象的成员(属性和方法)
            $this->name   $a->name  $a->say()
        ::
            范围操作符      前面是类    后面是静态属性静态方法以及常量
                A::$name  A::HOST   self::$name   parent::__construct()

clone
            用于克隆一个对象  会得到一个新对象

得到新对象的方式
            new
            unserialize
            clone

=
            用于取别名
        ==
            如果两个对象是同一个类的实例  并且所有的属性及值都相等  则相等
        ===
            用于判断是否是同一个对象

extends   用于继承
            继承特性
                PHP只支持单继承(只能有一个爹)
                PHP支持被多个继承(一个爹可以有多个儿子)
                PHP支持多层继承(祖宗关系)  A继承B  B继承C   那么A里面就有 A B C 里面所有内容
            属性的继承(重写  重构 重载)
                子类中出现与父类中同名属性则覆盖  如果子类中只定义不赋值  那么值为NULL
                权限只能扩大不能缩小(大小指的是有效范围)
                父类                子类
                public              public
                protected           protected  public
                private             private    protected   public
            方法的继承
                子类中的同名方法会覆盖父类中的方法
                参数个数应该和父类中保持一致
                参数是否有默认值也应该保持一致
                参数的默认值是什么  可以随意
                权限范围只能扩大不能缩小

##########################################################################
        __construct()        在使用new关键字的时候会自动调用  用于初始化
        __destruct()         在对象销毁的时候自动调用  用于回收资源

__get($key)          在本没有权限访问的地方访问属性
        __set($key,$val)     在本没有权限对属性赋值的时候
        __isset($key)        在本没有权限使用isset函数判断属性的时候
        __unset($key)        在本没有权限使用unset函数销毁属性的时候

__call($name,$list)  访问一个不存在的方法的时候
        __callStatic($name,$list)  
                            访问一个不存在的静态方法的时候
                            本身也需要是一个静态方法

__sleep()           在使用serialize函数将对象转换为字符串的时候自动调用
                            有一个数组类型的返回值,数组里面的字段是允许被保留的信息
        __wakeup()          在使用unserialize函数将字符串还原为对象的时候

__toString()        在将一个对象直接作为字符串输出的时候
                            必须有一个字符串类型的返回值

__clone()           在使用clone关键字克隆对象的时候自动调用

__autoload()        用于自动加载
                            在实例化一个对象  但是类不存在的时候  会自动调用
                            写在类的外面的,不要加类里面的关键字(public protected)
                            类名和文件名必须存在关联(通过类名可以拼接出文件名)

*/
    
//包含一个抽象方法的类就是抽象类  抽象类本身也需要使用 abstract修饰
 abstract class Animal{
        public $name;
        
        public function play(){
            echo '我在玩耍...<br>';
        }

//抽象方法
        //不能有方法体 必须以分号结尾
        //抽象方法必须被重写(因为本身是一个半成品)
        abstract public function eat();
    }

抽象类与抽象方法:
 /*
        作用:
            用于定义规范

抽象方法
            没有方法体的方法就是抽象方法
            抽象方法必须使用abstract修饰
            抽象方法不能有花括号
            抽象方法必须用分号结尾
            抽象方法必须被重写
        抽象类
            包含抽象方法的类就是抽象类
            抽象类也必须使用abstract修饰
            抽象类不能直接实例化
            抽象类需要被继承之后实现所有方法后才能实例化
            如果一个类继承了抽象类,但是没有实现所有抽象方法,那么这个类也是抽象类

*/
    
 /*
    抽象方法与接口的差异:
        抽象类中除了抽象方法方法还可以有普通方法。
        接口里面多有的方法都是抽象方法
  */

/*
        多态:不同的人做相同的是,得到不同的结果。
        比如几个小伙伴去面试,同一个面试官,有些录取了,有些
        没有录取。
    */

//妹子与屌丝和高富帅约会的不同场景。
    
 /*
        接口技术

接口的定义
        interface 接口名{
            [常量]
            [抽象方法]
        }

实现接口使用 implements 关键字
        接口可以多实现
    */
    
  interface USB{
        const WIDTH = 100;

//在接口中只能出现抽象方法
        //既然所有方法都是抽象方法  就没有必要用abstract标识了
        public function run();

public function cha();
    }

interface PS2{
        public function test();
    }

//接口使用 implements 实现  可以实现多个接口
    class Computer implements USB,PS2{
        public function run(){}
        public function cha(){}
        public function test(){}
    }

$p1 = new Computer;
    
//接口与接口也可以存在继承的关系  使用 extends 关键字
    interface Lenovo extends USB{
        public function gun();
    }

abstract class Gun{
        public function click(){
            
        }
        abstract public function move();
    }
    
    
$err = new Exception('人品太差,哥就是想报错');

//throw $err;

try{
        //尝试执行
        //将可能产生错误的代码写在这里
        echo '我来测试执行<br>';
        if($_GET['a'] > 5){
            throw new Exception('输入的数据不合法<br>');
        }

// throw 后续代码不执行  类似 return

echo '测试代码执行完毕<br>';
    }catch(Exception $ex){
        //捕获异常  抓去错误
        //如果在尝试执行的时候抛出了错误  直接执行这里
        echo $ex->getMessage();
    }

//退出上面的结构之后  后续代码继续执行

echo '我在后面排队呢。。。<br>';