在实例化和静态上下文中都能工作的PHP方法?
我正在尝试设置一些可以在实例化和静态上下文中调用的PHP方法。有什么好方法可以做到这一点?例如,我希望能够做到:在实例化和静态上下文中都能工作的PHP方法?,php,oop,design-patterns,methods,static-methods,Php,Oop,Design Patterns,Methods,Static Methods,我正在尝试设置一些可以在实例化和静态上下文中调用的PHP方法。有什么好方法可以做到这一点?例如,我希望能够做到: Foo::bar($item); foo($item)->bar(); 我可以设置两个单独的类,让每个函数修改thisArg并委托给另一个,但似乎有更好的方法。我能想到的只有一门课的唯一方法是这样: function foo($item = null) { return $item instanceof Foo ? $item : new Foo($item); }
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;
}
}
如果你看他们的代码,他们会这样做。我读过一些相关的文章,其中指出使用isset($this)
来确定上下文可能会引发警告,但似乎效果不错……对此有什么新的想法吗?另一种可能是创建两个类,一个包含所有静态版本的方法,然后是第二个用于委托给静态方法的类,如:
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;
}
}
Ideas?会这样做,但是当从静态上下文调用时,会发出一个E\u STRICT
粗略地说,创建一个静态的、实例可调用的方法目前还可以,但是这个特性很可能会被删除。也许有另一种方法可以满足你的需要
编辑:
如您所述,可以使用u调用模拟该功能,而无需抛出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()
);
?>
这是唯一可靠的解决方案。它适用于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');
不推荐使用:以下内容在PHP5.6中可用,但在PHP7.0中运行时会抛出一个E_DEPRECATED
错误,消息为“不应静态调用非静态方法foo::bar()。问题不在于您所说的isset($this),而在于让单个函数执行双重任务:要么是静态的,要么不是。PHP7.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');
不起作用:这会在PHP5.6和PHP7.0中抛出一个致命错误“Cannot redecaler 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');
也许在未来的版本中,一旦不推荐的用法被删除,我们就可以做到这一点。这正是我提出这个问题的原因。见鬼,这只是一种伪装!如果我想让一个数据库类作为静态单例调用,但能够在需要2个连接时实例化,该怎么办?@Cory,but
\u call
仅在对象上下文中调用不可访问的方法时触发但是静态方法在对象上下文中是可用的,所以我认为除非该方法不存在,否则它不会触发。不过我喜欢这个想法。@Cory checking$item==null
仅在不需要其他参数的情况下才有效。@YourCommonSense我认为当您只需要调用一个方法并立即返回时,静态版本会特别有用。OO读起来更干净,最好在链中调用几个方法,比如foo($item)->bar()->down()->The_street()->get()