🐘 通过几个栗子认识 PHP 闭包

阿轩的BUG
文章191
评论56
标签101
站点日志
作者总数:1位
置顶文章:0篇
标签总数:101条
文章总数:196篇
评论总数:56条
微语总数:201条
运行天数:2319天
最近更新:2026-07-28
文章标签
最新评论
Sherlock
2025-08-21
不是应该打包成apk文件吗,怎么突然就运行编译了,下一步呢
老金er
2025-05-25
人生设计非常必要,在信息化发达的今天,周围大部分人依然只能过着人生工程模式生活,长时间生活洗礼后,尽管“人生工程”已经不再适合很多人,他们也无法做出任何改变,人生设计给我们提供了新的思路,值得尝试
赏帮赚
2025-05-25
职场太多的尔虞我诈
三笑
2024-08-16
emlog6.0.1可以升级支持吗?
pony
2024-07-08
这篇文章提供了一种新的人生规划方法——"人生设计",它借鉴了产品设计的理念,鼓励人们以创造性和探索性的方式思考和规划自己的生活。以下是对这篇文章的几个评价维度: 创新性:将产品设计的理念应用于人生规划是一个新颖的视角,为人们提供了一种跳出传统生活轨迹,探索个性化生活路径的方法。 实用性:文章不仅提出了理念,还详细介绍了具体的实施步骤,包括自我评估、制定计划、原型设计和实践选择等,具有很强的操作性。 启发性:通过强调好奇心、不断尝试、重新定义问题等心态,文章鼓励人们打破常规,勇于探索未知,这对于激发个人潜能和创造力具有积极作用。 适应性:"人生设计"理念适用于不同人生阶段和不同背景的人,无论是希望从头开始的人,还是已经取得一定成就但希望探索新方向的人,都可以从中获得启发。 情感共鸣:文章对许多人对传统生活轨迹的不满和对改变的渴望进行了深刻的洞察,能够引起读者的共鸣。 可持续性:人生设计强调的是一个持续迭代和试错的过程,这与现实生活的发展规律相吻合,有助于人们在不断变化的环境中做出适应性调整。 教育意义:作为一种人生规划方法,"人生设计"可以作为教育的一部分,帮助年轻人更早地学会自我探索和规划,为未来的生活和职业发展打下基础。 局限性:尽管"人生设计"提供了一种新的思考框架,但它可能需要个人具备一定的自我认知和反思能力,对于一些缺乏自我探索经验的人来说,可能需要额外的指导和支持。 总体来说,这篇文章提供了一种有价值的人生规划方法,对于那些渴望改变、寻求个性化生活的人来说,是一种有益的参考和指导。
首页实用干货 🌋

匿名函数(Anonymous functions),也叫闭包函数(closures),允许 临时创建一个没有指定名称的函数。最经常用作回调函数(callback)参数的值。当然,也有其它应用的情况。

匿名函数目前是通过 Closure 类来实现的。

一、栗子1 用作于回调

$rs = preg_replace_callback('/-([a-z])/', function ($match) {
    return strtoupper($match[1]);
}, 'hello-world');

dump($rs); // "helloWorld"

二、栗子2 用作于变量赋值

$greet = function ($name) {
    dump($name);
};

dump($greet instanceof Closure); // true
$greet('PHP'); // "PHP"

三、栗子3 从父作用域继承变量

$message = 'hello';
$example = function () use ($message) {
    dump($message);
};
dump($example instanceof Closure); // true
$example(); // "hello"

四、栗子4的前提条件,简单理解 call_user_func_array() 和 call_user_func() 方法

  • call_user_func — 把第一个参数作为回调函数调用

function call_user_func (parameter) {}

该方法接收多个参数,第一个就是回调函数,可以是普通函数,也可以是闭包函数,后面的多个参数都是作为函数回调使用

$rs = call_user_func(function (...$params) {
    return func_get_args();
}, 1, 2, 3);
dump($rs); // [1,2,3]
  • call_user_func_array — 调用回调函数,并把一个数组参数作为回调函数的参数

function call_user_func_array (param_arr) {}
该方法接收2个参数,第一个就是回调函数,可以是普通函数,也可以是闭包函数,后面的数组参数都是作为函数回调使用

$rs = call_user_func_array(function (array $params) {
    return func_get_args();
}, [1, 2, 3]);
dump($rs); // [1,2,3]

五、栗子4 绑定闭包在指定对象

我的见解是将方法绑定到指定类上,使得方法也可以使用类的属性和方法,非常适合配合__call()魔术方法和call_user_func_array方法一起使用

  • Closure::bindTo — 复制当前闭包对象,绑定指定的$this对象和类作用域。
    function bindTo(newscope = ‘static’) { }
<?php
namespace PHP\Demo\Closure;

class ClosureBindTo
{
    public function __call($name, $arguments)
    {
        if (count($arguments) > 1 && $arguments[0] instanceof \Closure) {
            return call_user_func_array($arguments[0]->bindTo($this), array_slice($arguments, 1));
        }
        throw new \InvalidArgumentException("没有这个方法");
    }
}

// 测试
public function testClosureBindTo()
{
    $obj = new ClosureBindTo();
    $this->assertEquals(2, $obj->add(function (array $params) {
        return ++$params[0];
    }, [1]));

    // 测试同一个实例
    $newObj = $obj->test(function (array $params){
        return $this;
    }, [1]);
    $this->assertTrue($newObj instanceof $obj);
}
  • Closure::bind — 复制一个闭包,绑定指定的$this对象和类作用域。
    static function bind(Closure newthis, $newscope = ‘static’) { }
    bind函数是bindTo的静态表示
<?php
namespace PHP\Demo\Closure;

class ClosureBind
{
    private $methods = [];

    public function addMethod(string $name, \Closure $callback)
    {
        if (!is_callable($callback)) {
            throw new \InvalidArgumentException("第二个参数有误");
        }
        $this->methods[$name] = \Closure::bind($callback, $this, get_class());
    }

    public function __call(string $name, array $arguments)
    {
        if (isset($this->methods[$name])) {
            return call_user_func_array($this->methods[$name], $arguments);
        }

        throw new \RuntimeException("不存在方法[{$name}]");
    }
}

// 测试
public function testClosureBind()
{
    $obj = new ClosureBind();
    $obj->addMethod('add', function (array $params) {
        return ++$params[0];
    });
    $this->assertEquals(2, $obj->add([1]));

    // 测试同一个实例
    $obj->addMethod('test', function (array $params) {
        return $this;
    });
    $this->assertTrue($obj->test([1]) instanceof $obj);
}
上一篇
🆑 PHP代码整洁之道
下一篇
🥚 掌握移动端适配三种视口的价值所在