I'm trying to setup some PHP methods that are callable in instantiated and static contexts. What are some good ways to do this? For example I want to be able to do:
Foo::bar($item);
foo($item)->bar();
I could setup two separate classes and have each function modify the thisArg and delegate to the other, but it seems like there's got to be a better way. The only way I could think of to do it with only one class would be something like this:
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;
}
}
If you look at the code of underscore.php they do something like that. I've read some related questions from a while back which point out that using isset($this)
to determine the context can raise a warning, but it seems to work fine...any updated thoughts on that? Another possibility is could be to make two classes, one with all static version of the methods and then a second class that uses __call to delegate to the static method like:
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?
http://www.php.net/manual/en/domdocument.loadxml.php does this, but when called from a static context, issues an
E_STRICT
.Roughly, making a static and instance callable method will work for now, but that feature is likely to be removed. Perhaps there's another way to accomplish what you need?
edit: The functionality can be simulated with __call as you mention without throwing an
E_STRICT
, but you don't need two classes:This is the only reliable solution. It works with 5.3+ (except for that inline object instantiation at the bottom), but is somewhat unwieldy.
NOT RECOMMENDED: The following works in PHP 5.6 but throws an
E_DEPRECATED
error with the message "Non-static method foo::bar() should not be called statically" when run in PHP 7.0. The problem isn't with theisset($this)
as you say, but rather with having a single function do double duty: it's either static or it isn't. It is still supported in PHP 7.0, but you shouldn't rely on it.DOESN'T WORK: This throws a fatal error "Cannot redeclare foo::bar()" in both PHP 5.6 and PHP 7.0, but it would be ideal if you could do it this way instead.
Perhaps in future versions once the deprecated usage has been removed we'll be able to do that.