zoukankan      html  css  js  c++  java
  • php核心技术与最佳实践--- oop

    <?php
    /**
     * Created by PhpStorm.
     * User: cl
     * Date: 2019/8/12
     * Time: 7:08
     */
    /*oop*/
    class Person{
        public $name;
        public $gender;
        public function say(){
            echo $this->name,'is',$this->gender;
        }
    }
    
    $student = new Person();
    $student->name = "CL";
    $student->gender = "MAN";
    $student->say();
    // CLisMAN
    var_dump((array)$student);
    // array(2) { ["name"]=> string(2) "CL" ["gender"]=> string(3) "MAN" }
    // 对象由属性组成,一个对象的属性是它区别于另一个对象的关键所在。由于php的对象使用数组来模拟的
    // 因此我们把对象转成数组,就能看见这个对象所拥有的属性了。
    // 到这里,可以直观的认识到,对象就是一堆数据。既然如此,可以把一个对象存储起来,以便需要时用,这就是对象的序列化。
    $str = serialize($student);
    var_dump($str);
    // string(60) "O:6:"Person":2:{s:4:"name";s:2:"CL";s:6:"gender";s:3:"MAN";}"
    // 在需要时,可以反序列化取出这个对象
    var_dump(unserialize($str));
    // object(Person)#2 (2) { ["name"]=> string(2) "CL" ["gender"]=> string(3) "MAN" }
    // 可以看到,对象序列化后,存储的只是对象的属性。类是由属性和方法组成的,而对象则是属性的集合,由同一个类生成的不同对象,
    // 拥有各自不同的属性,但共享了类的代码空间中方法区域的代码。
    
    /*对象与数组*/
    // 数组是由键值对数据组成,数组的键值对和对象的属性/属性值对十分相似。对象序列化后和数组序列化后的结果是
    // 惊人的相似
    $student_arr = ['name' => 'CL' , 'gender' => 'MAN'];
    var_dump(serialize($student_arr));
    //  string(49) "a:2:{s:4:"name";s:2:"CL";s:6:"gender";s:3:"MAN";}"
    // 区别在于 : 对象中还包含指针,指向了它所属的类。
    
    /* 对象与类*/
    // 如果对象中还包含对象,那么序列化后会是什么样子呢?
    class Family{
        public $people;
        public $location;
        public function __construct ($p,$loc){
            $this->people = $p;
            $this->location = $loc;
        }
    /*    public function __destruct(){
            var_dump('魔术方法之析构方法');
        }*/
    }
    $tom = new Family($student,"peking");
    var_dump(serialize($tom));
    // string(118) "O:6:"Family":2:{s:6:"people";O:6:"Person":2:{s:4:"name";s:2:"CL";s:6:"gender";s:3:"MAN";}s:8:"location";s:6:"peking";}"
    /* 可以看出,序列化后的对象会附带所属类型,这个类名保证此对象在执行类的方法(也是自己所能执行的方法)时,
        能够正确地找到方法所在的代码空间(即对象所拥有的方法存储在类里)。另外,当一个对象的实例变量引用其他对象时,序列化对象
        也会对引用对象进行序列化
        由此可以分析二者的关系 :
        类是定义一系列属性和操作的模板,而对象则是把属性进行具体化,然后交给类处理
        对象就是数据,对象本身包含方法。但是对象有一个”指针“指向一个类,这个类里可以有方法。
        方法描述不同属性导致的不同表现
        类和对象是不可分割的,有对象就必定有一个类与其对应,否则这个对象也就成了没有亲人的孩子(但有一个特殊的情况,就是
        由标量进行强制类型转换的object,没有一个类与它对应。此时,PHP中一个称为”孤儿“的stdClass类就会收留这个对象)
        可以看出,在面向对象层面,js和php区别还是很大的。
    */
    
    /*魔术方法*/
    /*
     * 魔术方法是以两个下划线开头,具有特殊作用的一些方法,可以看作是PHP的语法糖
     * 语法糖是指那些没有给计算机添加新功能,而对人类来说更甜蜜的语法
     * Family类的__construct方法就是一个标准的魔术方法。这个魔术方法又称构造方法。具有构造方法的类会每次创建对象时
     * 先调用此方法,所以非常适合在使用对象之前做一些初始化工作,如:给属性赋值,连接数据库等
     * 有构造方法就有析构方法,即destruct方法,这个方法会在某个对象的所以引用都被删除,或者当对象被显式销毁时执行。
     * 这两个方法是最常见也是最有用的魔术方法
     */
    /*魔术方法之set 和 get*/
    class Account{
        private $user = 1;
        private $pwd = 2;
    
        public function __get($name){
            echo '请求'.$name;
        }
        public function __set($name,$val){
            echo "请求设置".$name."为".$val;
        }
    
    
        public function __call($name ,$arguments){
            // $name : 要调用的方法名称
            // $arguments : 数组,包含着要传递给方法的参数
            var_dump($name);
            var_dump($arguments);
        }
        public static function __callStatic($name ,$arguments){
            var_dump($name);
            var_dump($arguments);
        }
        public function __toString()
        {
            return '任意字符串';
        }
    
    }
    $a = new Account();
    $a->user; // 如果没有 __get 魔术方法则会报错,大致意思是不能访问对象的私有属性
    // 请求user
    $a->name = '123'; // 因为对象没有name属性,所以会触发 __set 魔术方法
    // 请求设置name为123
    /*
     * 可以直观的看到,若类中定义了set 和 get这一对魔术方法,那么当给对象属性赋值或取值时,即使
     * 这个属性不存在,也不会报错,一定程度上增强了程序的健壮性
     */
    // 那么,如果防止调用一个不可访问的方法(如未定义,或者不可见)时,call()会被调用。
    $a->demo('1','2');
    // "demo"
    // array(2) { [0]=> string(1) "1" [1]=> string(1) "2" }
    // 当调用的静态方法不存在或权限不足时,callStatic() 会被调用
    Account::demo();
    // "demo"
    // array(0) { }
    
    // 当然,使用魔术方法"防止调用不存在的方法而报错",并不是魔术方法的本意。实际上,魔术方法使方法的动态创建变为可能。
    // 这在MVC等框架设计中是很有用的语法。可以通过一段代码使用callStatic这一魔术方法进行方法的动态创建和延迟绑定
    
    // toString方法
    echo $a; //任意字符串
    // 比如打印一个对象时,看看这个对象都有哪些属性,其值是什么,如果定义了toString方法,就能在测试时,echo打印对象体
    // 对象会自动调用它所属类定义的toString方法,格式化输出这个对象所包含的数据。如果没有这个方法,那么echo一个对对象将报错
    <?php
    /**
     * Created by PhpStorm.
     * User: chenglin
     * Date: 2019/8/12
     * Time: 7:08
     */
    /*oop高级*/
    class Person{
        public $name = 'tom';
        public $gender;
        public $money = 1000;
        public function  __construct(){
            echo '这里是父类';
    
        }
        public function say(){
            var_dump( $this->name);
        }
    }
    class Family extends Person{
        public $name;
        public $gender;
        public $money = 100000;
        public function __construct(){
            parent::__construct();
            echo "这里是子类";
        }
        public function say(){
            parent::say();
        }
    }
    
    $poor = new Family();
    $poor->say();
    // 这里是父类
    // 这里是子类
    // NULL
    
    /*
     * 从上面的代码中可以了解继承的实现。在继承中,用parent指代父类,用self指代自身。
     * 使用"::"操作符(范围解析操作符)调用父类的方法。"::"操作符还可以作为类常量和静态方法的调用,不要把这两种应用混淆。
     * 既然提到静态,就再强调一点。如果声明类成员或方法为static,就可以不实例化类而直接访问
     */
    /*接口*/
    /*
     * 这里,首先强调一个概念,面向接口编程并不是一种新的编程范式。本章开头提到的三大范式中并没有提到面向接口。其实,
     * 这里是狭义的接口,即 interface 关键字。广义的接口可以是任何一个对外提供服务的出口,比如提供数据传输的usb接口,
     * 、淘宝网对其他网站开放的支付宝接口。
     * 接口定义一套规范,描述一个"物"的功能,要求如果现实中的"物"想成为可用,就必须实现这些基本功能。接口这样描述自己:
     *  "对于实现我的所以类,看起来都应该向我现在这个样子"
     * 在程序中,接口的方法必须被全部实现,否则会报fetal错误
     */
    interface mobile{
        public function run(); // 驱动方法
    }
    class plain implements mobile{
        public function run()
        {
            // TODO: Implement run() method.
            echo "我是飞机";
        }
        public function fly(){
            echo "飞行";
        }
    }
    (new plain())->fly();
    // 飞行
    // 思考: 接口本身并不提供实现,只要提供一个规范。
    // php中,接口的语义是有限的,使用接口的地方并不多,php中接口可以淡化为设计文档,起到一个团队基本契约的作用
    // 由于php是弱类型,且强调灵活,所以并不推荐大规模使用接口,而仅在部分"内核"代码中使用接口。从语义上考虑,
    // 可以更多地使用抽象类
    
    //抽象类
    abstract class Fruits{
        // 水果名称
        protected $name;
        // 抽象方法
        abstract public function eat();
        // 尽管不能实例化抽象类,但仍然可以有构造方法
        public function __construct(){
            echo "抽象构造器,实例化时自动调用" ;
        }
    }
    class Apple extends Fruits{
        protected $name = "苹果";
        public function eat(){
            echo $this->name . "可以直接生吃";
        }
        // 子类构造方法
        public function __construct()
        {
            echo parent::__construct();
        }
    }
    $apple = new Apple();
    echo $apple->eat();
    // 抽象构造器,实例化时自动调用
    // 苹果可以直接生吃
    
    // 抽象类提供了具体实现的标准,而接口则是纯粹的模板
    
    /*反射*/
    /*
     * 面向对象编程中对象被赋予了自省的能力,而这个自省的过程就是反射。
     * 反射,直观理解就是根据到达地找到出发地和来源。比方说:我给你一个光秃秃的对象,我可以
     * 仅仅通过这个对象就能直到它所属的类,拥有哪些方法
     */
    
    // 反射API
    $reflect = new ReflectionObject($apple);
    // 获取对象属性列表
    $props = $reflect->getProperties();
    foreach ($props as $prop){
        var_dump($prop->getName());
    }
    // string(4) "name"
    // 获取对象的方法列表
    $m = $reflect->getMethods();
    foreach ($m as $prop){
        var_dump($prop->getName());
    }
    //  string(3) "eat"
    //  string(11) "__construct"
    
    // 也可以不用反射API,使用class函数,返回对象属性的关联数组以及更多信息
    var_dump(get_object_vars($apple)); // 返回对象属性的关联数组
    // array(0) { }
    var_dump(get_class_vars(get_class($apple))); // 类属性
    // array(0) { }
    var_dump(get_class_methods(get_class($apple))); // 返回由类的方法名组成的数组
    // array(2) { [0]=> string(3) "eat" [1]=> string(11) "__construct" }
    
    // 在此。利用强大的反射API功能范元这个类的原型,包括方法的访问权限:
    $obj = new ReflectionClass('Apple');
    // 获取类型
    $className = $obj -> getName();
    // 初始化方法和成量数组
    $methods = $properties = [];
    foreach ($obj->getProperties() as $v){
        $properties[$v->getName()] = $v;
    }
    foreach ($obj->getMethods() as $v){
        $methods[$v->getName()] = $v;
    }
    echo "<br />class {$className}<br />{<br />";
    is_array($properties) && ksort($properties); // 数组排序
    // 遍历出类的属性
    foreach ($properties as $k => $v){
        echo "	";
        echo $v->isPublic() ? 'public' : '',$v->isPrivate() ? 'private' : '',$v->isProtected() ? 'protected' : '',
        $v->isStatic() ? 'static' : '';
        echo "	{$k}";
    }
    // 遍历出类的方法
    is_array($methods) && ksort($methods); // 数组排序
    foreach ($methods as $k => $v){
        echo "<br />function $k(){}";
    }
    echo "<br / >}";
    
    /*
        class Apple{
            protected    name
            function __construct(){}
            function eat(){}
        }
     */
    /*
     * 反射的作用: 用于文档生成。因此可以用它对文件里的类进行扫描,逐个生成描述文档
     *
  • 相关阅读:
    蓝桥杯 大数定理
    蓝桥杯 密码发生器
    简单定时器的使用
    Eclipse中更改Project Explorer的字体
    列的别名修改
    ||拼接字符串
    SQL知识总结
    java 打开记事本
    报表使用分组
    js处理异步问题
  • 原文地址:https://www.cnblogs.com/cl94/p/11343616.html
Copyright © 2011-2022 走看看