eloquent/pops

此包已被放弃,不再维护。未建议替换包。

PHP 对象代理系统。

5.0.0 2022-02-21 07:43 UTC

This package is auto-updated.

Last update: 2023-08-08 03:56:57 UTC


README

不再维护

此包不再维护。更多信息请参阅 此声明

Pops

PHP 对象代理系统。

安装和文档

什么是 Pops?

Pops 是一个将 PHP 对象包装在其他对象中以便修改其行为的系统。尽可能模仿其包装的对象的 Pops 代理。它将方法调用传递下去并返回底层结果,并允许透明访问属性(包括设置和获取)。

Pops 是 Liberator 的底层系统。

创建代理

让我们编写一个简单的代理,它将所有内容转换为 uppercase。这里有一个类

class Confusion
{
    public function wat()
    {
        return "What is this? I don't even...";
    }

    public $derp = 'Has anyone really been far even as decided to use even?';
}

这里是我们的代理

use Eloquent\Pops\ProxyObject;

class UppercaseProxyObject extends ProxyObject
{
    public function popsCall($method, array &$arguments)
    {
        return strtoupper(parent::popsCall($method, $arguments));
    }

    public function __get($property)
    {
        return strtoupper(parent::__get($property));
    }
}

我们在这里使用 popsCall() 而不是 __call(),以规避 PHP 有关通过引用传递参数的限制。有关更深入的解释,请参阅 通过引用参数调用方法

现在,当我们通过代理和正常方式访问 wat()$derp 时,我们可以看到效果

$confusion = new Confusion;
$proxy = new UppercaseProxyObject($confusion);

echo $confusion->wat(); // outputs "What is this? I don't even..."
echo $proxy->wat();     // outputs "WHAT IS THIS? I DON'T EVEN..."

echo $confusion->derp;  // outputs 'Has anyone really been far even as decided to use even?'
echo $proxy->derp;      // outputs 'HAS ANYONE REALLY BEEN FAR EVEN AS DECIDED TO USE EVEN?'

递归代理

Pops 代理可以递归地应用于任何值。当设计输出转义器(类似于 Symfony)时,这很有用。以下是一个如何为转义 HTML 输出创建此类系统的示例

namespace OutputEscaper;

use Eloquent\Pops\Proxy;

/**
 * Escapes output for use in HTML.
 */
class OutputEscaperProxy extends Proxy
{
    /**
     * Get the array proxy class.
     *
     * @return string The array proxy class.
     */
    protected static function proxyArrayClass()
    {
        return __NAMESPACE__ . '\OutputEscaperProxyArray';
    }

    /**
     * Get the class proxy class.
     *
     * @return string The class proxy class.
     */
    protected static function proxyClassClass()
    {
        return __NAMESPACE__ . '\OutputEscaperProxyClass';
    }

    /**
     * Get the object proxy class.
     *
     * @return string The object proxy class.
     */
    protected static function proxyObjectClass()
    {
        return __NAMESPACE__ . '\OutputEscaperProxyObject';
    }

    /**
     * Get the proxy class for primitive values.
     *
     * @return string The proxy class for primitive values.
     */
    protected static function proxyPrimitiveClass()
    {
        return __NAMESPACE__ . '\OutputEscaperProxyPrimitive';
    }
}
namespace OutputEscaper;

use Eloquent\Pops\ProxyArray;

/**
 * Wraps an array to escape any sub-values for use in HTML.
 */
class OutputEscaperProxyArray extends ProxyArray
{
    /**
     * Get the proxy class.
     *
     * @return string The proxy class.
     */
    protected static function popsProxyClass()
    {
        return __NAMESPACE__ . '\OutputEscaperProxy';
    }
}
namespace OutputEscaper;

use Eloquent\Pops\ProxyClass;

/**
 * Wraps a class to escape any sub-values for use in HTML.
 */
class OutputEscaperProxyClass extends ProxyClass
{
    /**
     * Get the proxy class.
     *
     * @return string The proxy class.
     */
    protected static function popsProxyClass()
    {
        return __NAMESPACE__ . '\OutputEscaperProxy';
    }
}
namespace OutputEscaper;

use Eloquent\Pops\ProxyObject;

/**
 * Wraps an object to escape any sub-values for use in HTML.
 */
class OutputEscaperProxyObject extends ProxyObject
{
    /**
     * Get the proxy class.
     *
     * @return string The proxy class.
     */
    protected static function popsProxyClass()
    {
        return __NAMESPACE__ . '\OutputEscaperProxy';
    }
}
namespace OutputEscaper;

use Eloquent\Pops\ProxyPrimitive;

/**
 * Wraps a primitive to escape its value for use in HTML.
 */
class OutputEscaperProxyPrimitive extends ProxyPrimitive
{
    /**
     * Get the HTML-escaped version of this primitive.
     *
     * @return string The HTML-secaped version of this primitive.
     */
    public function __toString()
    {
        return htmlspecialchars(
            strval($this->popsValue()),
            ENT_QUOTES,
            'UTF-8'
        );
    }
}

现在可以如此使用输出转义器

use OutputEscaper\OutputEscaperProxy;
use Eloquent\Pops\Safe\SafeProxy;

$list = new ArrayIterator(
    array(
        'foo',
        'bar',
        '<script>alert(document.cookie);</script>',
        SafeProxy::proxy('<em>ooh...</em>'),
    )
);
$proxy = OutputEscaperProxy::proxy($list, true);

echo "<ul>\n";
foreach ($proxy as $item) {
    printf("<li>%s</li>\n", $item);
}
echo "</ul>\n";

这将输出

<ul>
<li>foo</li>
<li>bar</li>
<li>&lt;script&gt;alert(document.cookie);&lt;/script&gt;</li>
<li><em>ooh...</em></li>
</ul>

请注意,上面的示例 不应 在生产中使用。输出转义是一个复杂的问题,不应轻率对待。

排除递归中的值

请注意,在上面的示例中,最后一个列表项被包装在一个 Safe 代理中。当 Pops 应用其代理时,它将跳过以这种方式标记为安全的内容。

通过引用参数调用方法

由于 PHP 的限制,必须以特殊方式调用具有引用参数的方法。

为了进一步解释,假设我们之前的类还有一个接受引用的方法

class Confusion
{
    public function butWho(&$wasPhone)
    {
        $wasPhone = 'Hello? Yes this is dog.';
    }
}

由于 $wasPhone 参数是通过引用传递的,此方法不能以常规方式代理。通过 Pops 代理调用上述 butWho() 方法的正确方式如下

use Eloquent\Pops\Proxy;

$proxy = Proxy::proxy(new Confusion);

$wasPhone = null;
$arguments = array(&$wasPhone);

$proxy->popsCall('butWho', $arguments);

echo $wasPhone; // outputs 'Hello? Yes this is dog.'

请注意,必须有一个变量用于$wasPhone参数,以及必须有一个变量用于参数本身。这两个都不能直接作为值传递。参数还必须包含对$wasPhone参数的引用