Method Calls with Arbitrary Names

A discovery of the day. Many people know that you can define and read an object property with an arbitrary name:

<?php

$s = new stdClass();
$s->{'any string here'} = 123;
echo $s->{'any string here'}; // 123

This is useful from time to time when parsing json for example:

<?php

$data = json_decode('{"any string here": 123}', false);
echo $data->{'any string here'};

It's a more rare knowledge that you can also call methods with this syntax. Probably because it's not usually useful, after all you cannot define a method with a name from an arbitrary string. However you can catch such call with a magic method:

<?php

$cc = new class() {
    public function __call($name, $arguments)
    {
        var_dump(func_get_args());
    }
};

$cc->{"any string here"}(123); // 'any string here', [123]

// also works with other indirect calls
call_user_func([$cc, "any string here"], 123);
$func = "any string here";
$cc->$func();

It works in all versions of PHP after 5.0: https://3v4l.org/3rCHF, also with static context and __callStatic since 5.3.

I don't know if this trick has many uses but for example it looks good as a Symfony EventSubscriber implementation.

<?php

use Psr\Container\ContainerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class EventSubscriber implements EventSubscriberInterface
{
    private ContainerInterface $container;

    public static function getSubscribedEvents()
    {
        return [
            SomeEvent::class => SomeListener::class,
        ];
    }

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    public function __call(string $name, array $arguments): void
    {
        $listener = $this->container->get($name);
        $listener->onEvent($arguments[0]);
    }
}

Comments

Comments powered by Disqus