I am open sourcing a trait which includes the magic method __call()
. During testing, I encountered a challenge when the parent class of the class using the trait contains the __call
method.
trait SomeTrait {
public function __call($method, array $parameters) {
// ...
return parent::__call($method, $parameters);
}
}
This results in the fatal error: Cannot access parent:: when current class scope has no parent
I also tried the following, based on some other answers:
return call_user_func_array([$this, '__call'], [$method, $parameters]);
This results in a Segmentation fault: 11. I imagine because of an infinite call loop.
How can I invoke the parent's __call
method from within the __call
method of the trait?
If it is not possible from within the trait directly, how might I invoke the parent's __call
method otherwise?
When you call a method on an object of the Str class and that method doesn't exist e.g., length() , PHP will invoke the __call() method. The __call() method will raise a BadMethodCallException if the method is not supported. Otherwise, it'll add the string to the argument list before calling the corresponding function.
Magic methods are special methods which override PHP's default's action when certain actions are performed on an object. Caution. All methods names starting with __ are reserved by PHP. Therefore, it is not recommended to use such method names unless overriding PHP's behavior.
Unlike traits in Scala, traits in PHP can have a constructor but it must be declared public (an error will be thrown if is private or protected). Anyway, be cautious when using constructors in traits, though, because it may lead to unintended collisions in the composing classes.
In PHP, a trait is a way to enable developers to reuse methods of independent classes that exist in different inheritance hierarchies. Simply put, traits allow you to create desirable methods in a class setting, using the trait keyword. You can then inherit this class through the use keyword.
Please check code below:
trait SomeTrait
{
public function __call($method, array $parameters)
{
// ...
return is_callable(['parent', '__call']) ? parent::__call($method, $parameters) : null;
}
}
class GreatParentClass
{
public function __call($method, array $parameters)
{
return 'bar';
}
}
class ParenClassWithoutCall
{
}
class ProxyClass extends GreatParentClass
{
}
class FooClass extends ProxyClass
{
use SomeTrait;
}
class BarClass extends GreatParentClass
{
use SomeTrait;
}
class BazClass extends ParenClassWithoutCall
{
use SomeTrait;
}
class SomeClassWithoutParent
{
use SomeTrait;
}
$class = new FooClass();
var_dump($class->foobar());
$class = new BarClass();
var_dump($class->foobar());
$class = new BazClass();
var_dump($class->foobar());
$class = new SomeClassWithoutParent();
var_dump($class->foobar());
This will print:
string(3) "bar"
string(3) "bar"
NULL
NULL
Sandbox with the code to check: http://3v4l.org/R8hI3
EDIT: I think this will cover all possibilities.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With