php-面向对象

  • 函数

    // 匿名函数也叫做闭包函数,允许临时创建一个没有指定名称的函数,最经常用作回调函数参数的值。
    
    
  • 类与对象

    // 1.类的定义
    class SimpleClass
    {
        // 声明属性
        public $var = 'a default value';
        // 声明方法 
        public function displayVar() {
            echo $this -> var
        }
    }
    
    /*
    $this说明
    假如类的对象去调用类里定义的方法,那么这个$this就是这个对象,如果是类去使用的话,那么这个$this是没有值的。
    
    关于$this,在php5和php7中有部分是不一样的
    
    假如有两个对象(a,b),这两个对象对应的类是不一样的,一个对象(a)里的方法调用了另一个类(b对象的类)里的方法,那个类里的方法有一个$this这个属性,那么此时这个$this的值应该是什么呢?
    
    1.在php5中,这个$this就是a这个对象
    2.在php7中,这个$this是没有值的
    */
    
    // 对象的创建,也就是类的实例
    $zhuyu = new People();
    // 也可以这样
    $className = 'People';
    $zhuyu = new $classNanme();
    
    // 对象赋值
    $zhuyu = new $People();
    $zhuchunyu = $zhuyu;
    $zhu = &$zhuyu;
    
    $zhuyu -> var = 'var';
    $zhuyu = null;
    
    var_dump($zhuyu);      // 输出值为null
    var_dump($zhu);		   // 输出值为null
    var_dump($zhuchunyu);   // 有输出值
    
    /*
    简化上面的结论,大概就是这样一段代码
    $b = $a;
    $c = &$a;
    $a = null;
    首先$b = $a;这行代码就是一个普通的赋值,那么$b所对应的$a所对应的值的内存地址,它和$a是是没有丝毫关系的
    再看$c = &$a;这是引用赋值吧,所以说$c对应的值的内存地址和$a所对应的值的内存地址是息息相关的,它是跟着$a所变换的
    最后$a = null;这也是一个普通的赋值,那么$a对应的是null的内存地址,之前$c的值是个$a的值是有关系的,所以$c也变成了null,$b的内存地址还是对应之前的内存地址。
    */
    
    // 创建新对象
    class Test
    {
        static public function getNew()
        {
            return new static;
        }
    }
    class Child extends Test{}
    
    $obj1 = new Test();
    $obj2 = new $obj1;
    var_dump($obj1 !== $obj2);     // ture
    
    $obj3 = Test::getNew();
    var_dump($obj3 instanceof Test);
    
    $obj4 = Child::getNew();
    var_dump($obj4 instanceof Child);
    
    /*
    方式一:通过new一个类去创建一个对象
    方式二:通过调用类里的方法,创建一个新对象
    */
    
    /*
    对象属性
    属性声明是由关键字开头:public protected private
    访问非静态属性方式:->
    访问静态属性方式:::
    */
    
    // 类常量
    class A 
    {
        const constant = 'constant value';
    }
    
    // 构造方法 __construct()  相当于python中的__init__()
    class People extends BaseClass
    {
        function __construct() {
            // 实力对象之前,先执行偶
            print '创建一个实例,先执行__construct';
            $this -> name = '朱春宇'
            // 调用父类的__construct(),
            parent::__construct();
        }
    }
    
    // 析构函数 __destruct 相对于python中 __del__方法
    // 在删除一个对象之前,会先执行__destruct方法
    class Test
    {
        function __destruct(){
            print 'del'.$this -> name . '\n'
        }
    }
    
    // 访问控制(可见性)
    /*
    对属性或者方法的访问控制,是通过在前面添加关键字public(公有),
    protected(受保护),pricate(私有)来实现的
    public:可以在任何地方都可以被访问
    protected:可以被自身及其子类和父类访问
    private:只能被它所在的类才能访问
    private相当于python中封装的思想,只能在类内部使用。
    */
    
    // 对象继承  extends
    /*
    子类继承父类,会继承父类所有的共有方法,受保护的方法,子类也可以重写父类的方法。
    */
    
    // 范围解析操作符(::)
    /*
    可以用来访问静态成员,类常量,还可以用于覆盖类的属性的方法和属性
    比如调用父类的方法 parent::__construct
    */
    
    // 静态关键字(static)
    /*
    声明类的属性或方法为静态,就可以不实例化类而直接访问,静态属性是不能通过类实例的对象去访问的,而静态方法是可以的
    访问静态属性和方法的方法都是::
    */
    
    // 抽象类实例
    abstract class Test
    {
        // 强制要求子类定义这些方法
        abstract public function getValue();
        abstract public function prefixValue();
        
        // 非抽象方法
        public function foo(){
            print '非抽象方法foo';
        } 
    }
    
    class Test1 extends Test
    {
        public function getValue()
        {
            // getvalue方法代码
        }
        public function prefixValue(){
            // prxfixValue方法代码
        }
    }
    /*
    对于抽象类的理解:
    1.和python中abc库差不多,控制子类的一些方法属性,必须有。
    2.达到上面抽象类的效果,也可以通过主动抛异常去实现,在父类定义一个函数,直接抛异常,如果继承他的类没有重写该方法,在使用到这个方法的时候,便会执行父类的方法,直接抛异常。
    */
    
    // 对象接口
    /*
    可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容
    
    接口是通过interface关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的
    
    接口中定义的所有方法都必须是公有,这就是接口的特性
    */
    
    // 声明一个'iTemplate'接口
    interface iTemplate
    {
        public function setVariable($name,$var);
        public function getHtml($template);
    }
    
    // 实现接口
    class Template implements iTemplate
    {
        private $vars = array();
        public function setVariable($name,$var)
        {
            $this -> vars[$name]=$var;
        }
        public function getHtml($template)
        {
            foreach($this->vars as $name=>$var){
                $template = str_replace('{'.$name.'}',$value,$template);
            }
            return $template;
        }
    }
    
    // 接口之间的继承,
    interface a
    {
        public function faa();
    }
    
    interface b extends a
    {
        public function fbb();
    }
    
    class c implements b
    {
        // 这个c如果想要实现a,b接口,那么必须要有a,b接口里的所有方法
        public function faa();
        public function fbb();
    }
    
    
    /*
    抽象类与接口之间相同之处和不同之处
    1.相同点
    - 两者都是抽象类,不能进行实例化
    - interface实现类及abstract class的子类都必须实现已经声明的抽象方法
    2.不同点
    - 接口实现需要implements,抽象类实现需要继承(extends)
    - 接口中声明的方法都必须是public(公有的),而抽象类声明的方法(这个方法带有abstract),可以是public,protected,但绝不能是private。如果抽象类中的方法是public类型的话,那么继承它的类的这个方法必须是public,如果抽象类中的方法是protected类型,那么
    继承它的类的方法应该是public或者protected类型。
    - 接口中声明的方法,只能是方法名,方法里面不能有代码块。抽象类中声明的方法可以有
    - 一个类可以实现多个接口,但是只能继承一个抽象类
    */
    
    
    // trait 一种代码复用的方法
    tarit speak {
        public function speakHello(){
            print 'hello'."\n";
        }
        $name = 'zhuyu';
    }
    
    class A
    {
        $name = 'zhuchunyu';
    }
    
    class B extends A{
        use speak;
    }
    
    b = new B();
    print b->name;
    
    // 匿名类
    /*比如一些函数需要的参数需要传递类,那么可以直接new 类名()*/
    
    // 重载:
    /*
    定义:是指动态地创建类属性和方法,我们是通过魔法方法来实现
    注意:1.所有重载方法都必须声明为public
    	 2.这些魔法方法的参数都不能通过引用传递
    	 3.php中的重载与其他绝大多数面向对象语言不同。传统的“重载”是用于提供多个同名的类方法,但各方法的参数类型和个数不同
    */
    // 属性重载
    /*
    - 在给不可访问属性赋值时,__set(%name,$value)会被调用。
    - 读取不可访问属性的值时,__get(%name)会别调用。
    - 当对不可访问属性调用isset()或empty()时,__isset()会被调用。
    - 当对不可访问属性调用unset()时,__unset()会被调用。
    */
    // 方法重载
    /*
    - __call:在对象中调用一个不可访问的方法时,被调用
    - __callStatic:在静态上下文中调用一个不可访问方法时,被调用
    */
    
    // 遍历对象 foreach
    class A
    {
        public $name = '朱宇';
        public $age = 18;
        public $sex = '男';
    
        protected $top = '1.71';
        private $a = 'aa';
    
        public function myForEach() {
            foreach ($this as $key=>$value){
                echo $key.'='.$value."\n";
            }
        }
    }
    
    $a = new A();
    
    foreach ($a as $item=>$value){
        echo $item.'='.$value."\n";
    }
    
    $a->myForEach();
    
    /*
    - 外面这个foreach的输入结果是没有protected,private的值的
    - 函数内部里的foreach可以显示所有的属性的
    - foreach它只能循环它能访问的属性
    */
    
    // 魔法方法
    /*
    1.__construct(),它会在new一个对象之前触发执行
    2.__destruct(),它会在del一个对象之前,运行。
    3.__call,它会在调用一个方法,并且这个方法不存在的时候执行
    4.__callStatic,它会在调用一个静态方法,并且这个方法不存在的时候执行
    5.__get(),获取一个对象的属性,并且这个属性不存在的话,那么便会执行这个魔法方法
    6.__set(),再给对象的一个属性赋值时,并且这个属性不能访问,那么就会执行这个方法
    7.__isset,执行isset()函数的时候,先执行
    8.__unset,执行unset()函数的时候,先执行
    9.__sleep(),在执行serialize()这个函数的时候,会检查类中是否存在该魔法方法,有的话,会先调用__sleep()这个方法,然后在执行序列化操作。这个方法的返回值应该是一个数组,如果这个方法没有返回值的话,那么null则会被序列化,并且产生一个E_noteic级别的错误。
    10.__wakeup(),会在执行unserialize这个函数的,会先执行该魔法方法。
    11.__toString(),这个方法在打印一个对象的时候,自动触发,返回值必须是字符串,和python中的__str__
    12.__invoke(),当尝试以调用函数的方法调用一个对象时,__invoke()自动触发,和python中__call__
    13.__set_state(),
    14.__clone(),
    15.__debuginfo(),
    16.__autoload(),
    */
    
    // final关键字
    // 如果父类中的方法被声明为final,则子类无法覆盖该方法,如果一个类被声明为final,则不能被继承
    // final方法示例
    class BaseClass
    {
        public function faa(){
            print 'faa'."\n";
        }
        final public function fbb(){
            print 'fbb'."\n";
        }
    }
    
    class AClass extends BaseClass
    {
        public function fbb(){
            print 'AClass fbb'."\n";
        }
    }
    
    $a = new AClass();
    $a->fbb();
    
    // final类实例
    final class BaseClass
    {
        public $name;
    }
    
    class AClass extends BaseClass{}
    
    $a = new AClass();
    echo $a ->name;
    
    
    // 对象复制 __clone方法
    class SubObject
    {
        static $instances = 0;
        public $instance;
    
        public function __construct() {
            $this->instance = ++self::$instances;
        }
    
        public function __clone() {
            $this->instance = ++self::$instances;
        }
    }
    
    class MyCloneable
    {
        public $object1;
        public $object2;
    
        function __clone()
        {
          
            // 强制复制一份this->object, 否则仍然指向同一个对象
            $this->object1 = clone $this->object1;
        }
    }
    
    $obj = new MyCloneable();
    
    $obj->object1 = new SubObject();
    $obj->object2 = new SubObject();
    
    $obj2 = clone $obj;
    
    
    print("Original Object:\n");
    print_r($obj);
    
    print("Cloned Object:\n");
    print_r($obj2);
    /*
    上面的打印的效果为   $obj -> object1为 1 ,$obj -> object2为 2
    				  $obj2 -> object1为 3 ,$obj -> object2为 2 
    首先__clone方法只有调用clone这个方法,才会去执行
    在执行$obj2 = clone $obj这行代码之前,$obj这个对象的的属性值为 object1为1,object2为2,
    在执行$obj2 = clone $obj这行代码的时候,首先会去执行$obj这个对象里的__clone方法,这个$obj是类MyCloneable的对象,那么就去看这个类里的__clone方法,这个方法执行这行代码$this->object1 = clone $this->object1;首先会执行clone $this->object1这行代码,$this->object1对应的是SubObject类的对象,便会执行该类里的__clone方法,此时$instances的值为2,那么执行__clone之后的话,$instance的值就是3了,最终的代码为 $this->object1 = 一个SubObject的对象,对象里$instance的值为3。
    */
    
    // 对象比较
    /*
    1.使用(==)双等号进行比较的话,比较的原则是:如果两个对象的属性和属性值都相等,并且两个对象是同一个实例,那么这两个对象变量相等。
    2.如果使用(===)全等符号,这两个对象变量一定要指向某个类的同一个实例(即同一个对象)
    
    思考  $a=$b它是怎么个过程,$a,$b都是一个对象
    */
    
    // 类型约束:在方法或者函数的参数之前,加一个类型,就是对参数的类型约束了。
    
    // 后期静态绑定
    /*
    用法:self::对当前类的静态引用,__CLASS__是当前对象的类名
    	 static::
    	 parent::执行器父类的方法
    */
    
    // 对象和引用
    /*
    关于这行代码 $a = $b,($b只是一个类的对象),在php的对象编程中,我觉得就是引用传递,$a,$b它们指向的内置地址都是同一个,所有一旦其中一个改变属性,对应的它对应的内存地址的值发生改变,所有另一个变量也会进行改变。
    */
    
    // 对象序列化
    /*
    php里面的值,都可以使用函数serialize()来返回一个包含字节流的字符串来表示,unseralize()函数则是能够把字符串重新转换为原来的php值。序列化一个对象会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字
    */
    
posted @ 2019-04-03 14:38  朱春雨  阅读(168)  评论(0编辑  收藏  举报