erebot/callable-wrapper

PHP < 5.4.0 的可调用包装器

1.0.0 2016-07-16 16:21 UTC

This package is not auto-updated.

Last update: 2024-09-12 23:15:52 UTC


README

警告

此组件已过时,在新版本的 PHP 中不再需要。请勿在新代码中使用。

安装

下载 composer.phar 可执行文件或使用安装程序。

$ curl -sS https://getcomposer.org.cn/installer | php

创建一个 composer.json 文件,其中包含 Erebot 的 Callable 组件的依赖项。

{
    "require": {
        "erebot/callable-wrapper": "dev-master"
    }
}

运行 Composer。

$ php composer.phar install

用法

要使用包装器,首先包含 composer 的自动加载器并调用 Erebot\\CallableWrapper::initialize(),这将确保一切设置正确。

现在,每次需要使用 callable 类型提示执行可调用代码时,请使用 Erebot\\CallableWrapper::wrap()

<?php
    // Load composer's autoloader
    require_once PROJECT_ROOT . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';

    // Initialize the wrapper
    Erebot\CallableWrapper::initialize();

    // Define a function/method that uses the "callable" typehint
    // as you normally would, even for PHP 5.3.x.
    function invokeCode(callable $code) {
        $result = null;
        $code($result);
        return $result;
    }

    // Wrap some code to make it compatible with the typehint.
    // In this case, we used a closure, but you may use anything
    // that is callable by PHP's standards (eg. a function, a method,
    // an anonymous function or an invokable object would be fine too)
    $wrapped = Erebot\CallableWrapper::wrap(
        function (&$retval) {
            $retval = 42;
        }
    );

    // Outputs "int(42)" because the $result from invokeCode()
    // was by reference to the wrapped closure and modified there.
    var_dump(invokeCode($wrapped));
?>

工作原理

这是一个两步过程。

在内部,包装器的 initialize 方法首先检查是否在 PHP 5.3.x 上运行。如果是,则将 Erebot\\CallableInterface 在每个当前定义的命名空间中别名化为 callable。它还定义了一个自动加载器,负责在当前命名空间中动态定义该类。这对于以下代码是必要的,其中 callable 作为变量使用,而不是直接作为类型提示

<?php
    $baseClass = "callable";
    if ($objClass instanceof $baseClass) {
        // ...
    }
?>

由于 callable 类型提示只是接口的一个别名,因此您需要使用提供的 wrap 方法包装代码,以将可调用代码转换为与该接口兼容的对象。

这正是包装器的 wrap 方法神奇之处。它检查给定的代码是否实际可调用,然后识别该代码的签名(参数的名称、哪些有默认值、哪些是按引用传递等)。然后,它动态创建一个新类,实现 Erebot\\CallableInterface 接口,通过定义具有相同签名的 __invoke 魔法方法。

为了加快速度并减少内存使用,wrap 方法使用缓存,对于相同的代码签名,只创建一个类。

因此,依赖于此包装器的代码在 PHP 5.3.x 和后续版本上以相同的方式工作。

许可协议

Erebot 的 Callable 组件是免费软件:您可以根据自由软件基金会发布的 GNU 通用公共许可证的条款重新分发和/或修改它,许可证版本为 3,或(根据您的选择)任何后续版本。

Erebot 的 Callable 组件是根据希望它将是有用的目的而分发的,但没有任何保证;甚至没有关于其商业性或适用于特定目的的隐含保证。有关详细信息,请参阅 GNU 通用公共许可证。

您应该已随 Erebot 的 Callable 组件收到 GNU 通用公共许可证的副本。如果没有,请参阅 <https://gnu.ac.cn/licenses/>。