1

我正在尝试设置一些可在实例化和静态上下文中调用的 PHP 方法。有什么好的方法可以做到这一点?例如我希望能够做到:

Foo::bar($item); 
foo($item)->bar();

我可以设置两个单独的类,并让每个函数修改 thisArg 并委托给另一个,但似乎必须有更好的方法。我能想到的唯一方法是只用一个类来做到这一点:

function foo($item = null) {
    return $item instanceof Foo ? $item : new Foo($item);
}

class Foo { 
    protected $wrapped;

    public function __construct($item = null) { 
        $this->wrapped = $item;
    }

    public function get() {
        return $this->wrapped;
    }

    public function bar($item = null) {
        isset($this) and $item = &$this->wrapped;
        // do stuff with $item
        return isset($this) ? $this : $item;
    }
}

如果您查看underscore.php的代码,他们会执行类似的操作。我已经阅读了一些相关的问题,这些问题指出使用isset($this)来确定上下文可以引发警告,但它似乎工作正常......对此有任何更新的想法吗?另一种可能性是创建两个类,一个具有所有静态版本的方法,然后另一个类使用__call委托给静态方法,例如:

class _Foo
{
        protected $wrapped;

        public function __construct($item = null) { 
            $this->wrapped = $item;
        }

        public function __call($method_name, $args) { 
            array_unshift($args, $this->wrapped);
            $this->wrapped = call_user_func_array('Foo::' . $method_name, $args);
            return $this;
        }


}

想法?

4

2 回答 2

2

http://www.php.net/manual/en/domdocument.loadxml.php会这样做,但是当从静态上下文调用时,会发出一个E_STRICT.

粗略地说,制作一个静态和实例可调用的方法现在可以工作,但该功能可能会被删除。也许还有另一种方法可以完成您的需要?

编辑:正如您提到的,可以使用 __call 模拟功能而无需抛出E_STRICT,但您不需要两个类:

<? //PHP 5.4+
class mightBeInstance
{
    public function __call($name, $arguments)
    {
        if ($name === 'doSomething') {
            return static::doSomething($this);
        }
    }

    public static function doSomething(mightBeInstance $item = null)
    {
        if ($item === null) {
            $item = new static();
        }

        $item->didSomething = true; // Or whatnot

        return $item;
    }
}

var_dump(
    (new mightBeInstance)->doSomething(),
    mightBeInstance::doSomething()
);

?>
于 2012-05-04T05:04:52.443 回答
0

这是唯一可靠的解决方案。它适用于 5.3+(除了底部的内联对象实例化),但有点笨拙。

class foo {
    protected function __call($method, $args) {
        if ($method == 'bar') {
            return $this->bar($args[0]);
        }
    }
    protected function bar($baz) {
        return "object context: $baz\n";
    }

    public static function __callStatic($method, $args) {
        if ($method == 'bar') {
            return self::barStatic($args[0]);
        }
    }
    protected static function barStatic($baz) {
        return "static context: $baz\n";
    }
}

echo foo::bar('baz');
echo (new foo())->bar('baz');

不推荐:以下在 PHP 5.6 中有效,但E_DEPRECATED在 PHP 7.0 中运行时会抛出错误消息“非静态方法 foo::bar() 不应被静态调用”。问题不在于isset($this)您所说的,而是让一个函数执行双重任务:它要么是静态的,要么不是。PHP 7.0 仍然支持它,但你不应该依赖它。

class foo {
    public function bar($baz) {
        if (isset($this)) {
            return "object context: $baz\n";
        } else {
            return "static context: $baz\n";
        }
    }
}

echo foo::bar('baz');
echo (new foo())->bar('baz');

不起作用:这会在 PHP 5.6 和 PHP 7.0 中引发致命错误“无法重新声明 foo::bar()”,但如果您可以这样做,那将是理想的选择。

class foo {
    public function bar($baz) {
        return "object context: $baz\n";
    }
    public static function bar($baz) {
        return "static context: $baz\n";
    }
}

echo foo::bar('baz');
echo (new foo())->bar('baz');

也许在未来的版本中,一旦删除了不推荐使用的用法,我们就可以做到这一点。

于 2015-10-01T02:52:46.793 回答