PHP Closure(闭包)

类摘要

  • __construct() 空的构造函数,禁止实例化
  • public static bind (Closure $closure, object $newthis [, mixed $newscope = 'static']):Closure 复制一个闭包,绑定指定的 $this 对象和类作用域
  • public BindTo(object $newthis [, mixed $newscope = 'static']):Closure 复制当前闭包对象,绑定指定的$this 对象和类作用域

普通方法与匿名方法

<?php
// 声明方法 func
function func() {
    return 'hello world';
}

// 匿名函数
$func = function() {
    return 'hello world';
};

// hello world
echo func();
// hello world
echo $func();

闭包的实现

将匿名函数作为参数,实现闭包

如果需要将一个方法作为另一个方法的参数,就需要使用匿名方法来实现,声明的普通方法不能被直接被用来当作参数,对于将匿名函数作为参数传入普通函数中;这就实现了一个简单的闭包

<?php
function func2(Closure $closure) {
    return $closure();
}

// func 是一个方法,不能作为 func2 的参数;
// $func 是一个变量(指向一个匿名函数),可以作为 func2 的参数;
// hello world
echo func2($func);

// 等同于 func2($func);
// hello world
echo func2(function(){
    return 'hello world';
});

在函数中定义匿名函数,实现闭包

将匿名函数在普通函数中被定义,并在普通函数中被执行;这也实现了一个简单的闭包

<?php
function echoStr() {
    $func = function($str) {
        echo $str;
    };
    $func('hello world');
}
// hello world
echoStr();

将匿名函数作为返回值,实现闭包

将匿名函数在普通函数中被定义,并作为普通函数的返回值;这也实现了一个简单的闭包

<?php
function getEchoStrFunc() {
    $func = function($str) {
        echo $str;
    };
    return $func;
}
$echoStrFunc = getEchoStrFunc();
// hello world
$echoStrFunc('hello world');

闭包的绑定

<?php
// public static bind (Closure $closure, object $newthis [, mixed $newscope = 'static']):Closure
// bind 是 bindTo 的静态版本
// closure 需要绑定的匿名函数
// newthis 匿名函数绑定到的对象,或者null创建未绑定的闭包
// newscope 想要绑定给闭包的类作用域,或者 static 表示不改变。如果传入一个对象,是使用这个对象的类型名。类作用域用来决定在闭包中$this对象的私有、保持方法的可见性

匿名函数的绑定,访问类的公有成员

<?php
// 定义一个类 User,其有一个 age 属性,默认值为17
class User {
    public int $age = 17;
}

// 定义匿名函数 $func3,并在其中使用了 this 关键字
$func3 = function() {
    return $this->age + 1;
};

// this 关键字,需要在类中进行使用,如果直接进行调用,将会出现 Fatal error: Uncaught Error: Using $this when not in object context
// echo $func3();

// public static bind (Closure $closure, object $newthis [, mixed $newscope = 'static']):Closure
// $func3 需要绑定到一个类中,才能进行使用
$a = Closure::bind($func3, new User);
// 18
echo $a();

静态匿名函数的绑定,访问类的静态成员

<?php
// 定义一个类 User,其有一个 age 属性,默认值为17;一个 name 属性
class User {
    private static $name = 'Jason';
    public int $age = 17;
}

$getName = static function() {
    return self::$name;
};

// Cannot bind an instance to a static closure
// $b = Closure::bind($getName, new User);
// echo $b();

$b = Closure::bind($getName, null, new User);
// Jason
echo $b();

匿名函数绑定,访问类的私有成员

<?php
// 定义一个类 User,其有一个 age 属性,默认值为17;一个 name 属性,一个 last_name 属性
class User {
    private static $name = 'Jason';
    public int $age = 17;
    private $last_name = 'Zhang';
}

$getLastName = function() {
    return $this->last_name;
};

// Fatal error: Uncaught Error: Cannot access private property User::$last_name
// $c = Closure::bind($getLastName, new User);
// echo $c();

$c = Closure::bind($getLastName, new User, 'User');
// Zhang
echo $c();

闭包的动态绑定

<?php
// 定义一个实现动态绑定的 trait
trait DynamicFunc {
    public function __call($name, $args) {
        if (is_callable($this->$name)) {
            return call_user_func($this->$name, $args);
        } else {
            throw new \Exception('Method ' . $name . ' does not exists.');
        }
    }
    public function __set($name, $value) {
        // bindTo($this) 只能访问公有属性
        // bindTo($this, $this) 访问私有属性
        $this->$name = is_callable($value) ? $value->bindTo($this, $this) : $value;
    }
}

// 定义一个类 User,其有一个 age 属性,默认值为17;一个 name 属性,一个 last_name 属性;通过 use 引入 trait DynamicFunc
class User {
    use DynamicFunc;
    private static $name = 'Jason';
    public int $age = 17;
    private $last_name = 'Zhang';
}

$user = new User();
// 通过调用 __set 给实例添加 getLastName 方法
$user->getLastName = function() {
    return $this->last_name;
};

// Zhang
echo $user->getLastName();

发表评论

您的电子邮箱地址不会被公开。