深入PHP 面向对象、模式与实践 第4章 高级特性


深入PHP 面向对象、模式与实践 第4章 高级特性


正文

本章包括以下内容:

  • 静态方法和属性:通过类而不是对象来访问数据和功能。
  • 抽象类和接口:设计和实现相分离。
  • 错误处理:异常。
  • Final类和方法:限制继承。
  • 拦截器方法:自动委托。
  • 析构方法:对象销毁前的清理工作。
  • 克隆对象:创建对象的副本。
  • 把对象解析成字符串:创建摘要型方法。
  • 回调:用匿名函数为组件添加功能。

魔术方法:

__construct()      构造方法,当一个对象被创建时调用此方法
__destruct()       析构方法,在对象被销毁前(即从内存中清除前)调用这个方法
__call($method, $arg_array)      当调用一个未定义(包括没有权限访问)的方法是调用此方法
__callStatic()       类似于 __call() 魔术方法,__callStatic() 是为了处理静态方法调用
__get($property)     当调用一个未定义的属性时访问此方法
__set($property, $value)     给一个未定义的属性赋值时调用
__isset($property)       在一个未定义的属性上调用isset()函数时调用此方法
__unset($property)       当在一个未定义的属性上调用unset()函数时调用此方法
__sleep()      serialize()串行化的时候用
__wakeup()     unserialize()反串行化的时候调用
__serialize()      serialize()串行化的时候用
__unserialize()    unserialize()反串行化的时候调用
__toString()     将一个对象转化成字符串时自动调用
__invoke()      当尝试以调用函数的方式调用一个对象时
__set_state()     当调用var_export()时,这个静态方法会被调用
__clone()     复制一个对象时自动调用
__debugInfo()    打印所需调试信息
__autoload()     使用尚未被定义的类时自动调用,spl_autoload_register()也可以

超级全局变量:

$GLOBALS  储存全局作用域中的变量
$_SERVER  获取服务器相关信息
$_REQUEST  获取POST和GET请求的参数
$_POST  获取表单的POST请求参数
$_GET  获取表单的GET请求参数
$_FILES  获取上传文件的的变量
$_ENV  获取服务器端环境变量的数组
$_COOKIE    浏览器cookie的操作
$_SESSION  服务端session的操作

魔术变量:

__LINE__  文件中的当前行号。
__FILE__  文件的完整路径和文件名。如果用在被包含文件中,则返回被包含的文件名。
__DIR__  文件所在的目录。如果用在被包括文件中,则返回被包括的文件所在的目录。
__FUNCTION__  常量返回该函数被定义时的名字
__CLASS__  常量返回该类被定义时的名字(区分大小写)。
__METHOD__  类的方法名(PHP 5.0.0 新加)。返回该方法被定义时的名字(区分大小写)。
__NAMESPACE__  当前命名空间的名称(区分大小写)。此常量是在编译时定义的(PHP 5.3.0 新增)。

使用举例:

/**
 * 魔术方法类
 * 系统在特定的时机调用的方法称为魔术方法
 */
class Magic 
{
    public $name;       //公共的
    protected $age;        //受保护的 
    private $height;    //私有的
 
    //在内外实例化对象的时候自动调用此方法,一般用来初始化某些变量
    public function __construct($name,$age,$height)    {
        $this->age = $age;
        $this->name = $name;
        $this->height = $height;
    }
 
    //在类外调用受保护的以及私有的成员属性时自动执行该方法
    //或者在调用不存在的属性是自动执行该方法
    public function __get($name) { //参数为:类外调用属性的属性名称
        echo $name."该属性你没有权限进行调用或者该属性不存在".'<br/>';
    }
 
    //在类外调用受保护的以及私有的成员属性设置值的时候自动执行此方法
    //或者类中不存在的属性设置值的时候    
    public function __set($name,$value) {//参数为:类外调用属性的属性名称以及对属性需要设置的值
        $this->$name = $value.'<br/>';
    }
 
    //在类外调用一个不存在的普通方法时,调用此方法  
    public function __call($name,$value) { //参数为:类外调用的方法名称以及调用此方法时传递的参数
        echo $name."这个普通方法不存在,你调用这个不存在方法传递的值为".'<br/>';
        var_dump($value).'<br/>';
    }
 
    //在类外调用一个不存在的静态方法时,调用此方法  !!!注意,此方法本身必须是一个静态方法,使用static修饰过的方法称为静态方法
    public static function __callStatic($name, $arguments) { //参数为:类外调用的方法名称以及调用此方法时传递的参数
        echo $name."这个静态方法不存在,你调用这个不存在方法传递的值为".'<br/>';
        print_r($arguments); // 输出调用不存在的方法时的参数列表
    }
 
    //在类外销毁受保护的以及私有的成员属性时调用此魔术方法
    public function __unset($name) { //参数为:类外销毁属性的属性名称
        echo $name."权限很高,就是不让你销毁啊".'<br/>';
    }
 
    //在类外判断受保护的以及私有的成员属性是否设置时调用此魔术方法
    public function __isset($name) { //参数为:类外判断属性的属性名称
        echo $name."权限很高,你在类外就是不给你判断呀".'<br/>';
    }
 
    //将类实例化为对象之后,使用clone克隆这个类的时候调用此方法,可以在此设置克隆的类的成员属性
    public function __clone() {
        $this->name = '小羽';
        $this->age = '18';
        $this->height = '165';
    }
 
    //在类外实例化这个对象之后,序列化这个对象之后调用此方法  作用为只序列化这个方法中返回的成员属性
    public function __sleep() {
        return ['age','height'];
    }
 
    //在类外实例化这个对象之后,反序列化的时候调用此方法  可以在反序列化的时候重新初始化成员属性
    public function __wakeup() {
        $this->name = '小羽';
        $this->age = '18';
        $this->height = '165';
    }
 
    //将类实例化为对象的时候,echo对象调用此方法。!!!注意,此方法内只能return不能echo
    public function __toString() {
        return "你是不是闲得慌,没事你去输出对象,有病啊".'<br/>';
    }
 
    //将类实例化为对象的时候,打印对象时调用此方法,打印此方法返回的数组   5.6之后才有这个魔术方法
    public function __debugInfo() {
        return ['age'=>$this->age,'height'=>$this->height];
    }
    
    
    public function __invoke($param){
        var_dumo($param);  //参数就是你传递的数值
        return 这里是将实例化之后的类当成方法进行调用时触发的魔术方法;
    }
 
    //执行完脚本之后会自动调用此方法
    public function __destruct() {
        echo '你就这么不要我了吗?'.'<br/>';
    }
}
 
//这是唯一的一个写在类外的魔术方法,在实例化一个不存在的类的时候就会调用此方法,可以用在需要某些类但是没有引入的情况
function __autoload($className) {
    $file = $className.'.php';
    include $file;
}

回调、匿名函数和闭包

在类中可以使用 call_user_func()array_walk() 等函数回调。参数可以是匿名函数、类方法、闭包。

利用回调,你可以在运行时将与组件的核心任务没有直接关系的功能插入到组件中。

看个例子:

ProcessSale.php

<?php
declare(strict_types=1);

namespace popp\ch04\batch23;

class ProcessSale
{
    private $callbacks;

    public function registerCallback(callable $callback)
    {
        if (! is_callable($callback)) {
            throw new Exception("callback not callable");
        }
        $this->callbacks[] = $callback;
    }

    public function sale(Product $product)
    {
        print "{$product->name}: processing \n";
        foreach ($this->callbacks as $callback) {
            call_user_func($callback, $product);
        }
    }
}

Product.php

<?php
declare(strict_types=1);

namespace popp\ch04\batch23;

class Product
{
    public $name;
    public $price;

    public function __construct(string $name, float $price)
    {
        $this->name = $name;
        $this->price = $price;
    }
}

Runner.php

<?php
declare(strict_types=1);

namespace popp\ch04\batch23;

class Runner
{
    public static function run()
    {
        $logger = create_function(
            '$product',
            'print "    logging ({$product->name})\n";'
        );

        $processor = new ProcessSale();
        $processor->registerCallback($logger);

        $processor->sale(new Product("shoes", 6));
        print "\n";
        $processor->sale(new Product("coffee", 6));
    }

    public static function run2()
    {
        $logger2 = function ($product) {
            print "    logging ({$product->name})\n";
        };

        $processor = new ProcessSale();
        $processor->registerCallback($logger2);

        $processor->sale(new Product("shoes", 6));
        print "\n";
        $processor->sale(new Product("coffee", 6));
    }
}






参考资料

深入PHP面向对象,模式与实践 第4章:高级特性 https://blog.csdn.net/YQXLLWY/article/details/82937323

第4章:高级功能 https://www.jianshu.com/p/c9110bc8c9f4

《深入PHP 面向对象、模式与实践(第3版)》 https://ibaiyang.github.io/blog/books/深入PHP面向对象模式与实践.pdf

PHP之十六个魔术方法详解 https://segmentfault.com/a/1190000007250604

PHP 的魔术方法 https://blog.csdn.net/haif_city/article/details/83180344


返回