Re: [Proposal] call_user_func_map(): flexible named parameter mapping for call_user_func*

From: Date: Thu, 01 Jul 2021 16:55:29 +0000
Subject: Re: [Proposal] call_user_func_map(): flexible named parameter mapping for call_user_func*
References: 1 2 3 4  Groups: php.internals 
Request: Send a blank email to internals+get-115268@lists.php.net to get a copy of this message

What I don't understand is what the issue with that is? You can already build up a named array and splat it into a function call to pass by name. It's a really neat trick. It doesn't need a dedicated function. About a month ago, I went through all of TYPO3 and removed all remaining call_user_func_array() calls in favor of just $function(...$args), because it does the same thing and is faster, and easier to read. Named arguments already work exactly that way, too. I don't see an advantage to adding a function that does what you can already do with less syntax: $args['foo'] = 5; $args['beep'] = get_value_from_db(); $args['narf'] = 'poink'; $callable(...$args); That works today in 8.0. We're good.
The proposal focuses on the onus put on the author of the closure/function, not the caller. If your $callable is only interested in $foo enforced as an int and $narf enforced as a string, what does the signature and body of the subscribing $callable look like in this case? I am proposing that if a system is providing all of this for any registered callables: $args['foo'] = 5; $args['beep'] = get_value_from_db(); $args['narf'] = 'poink'; $args['boop'] = $boopObject; $args['isNoomable'] = false; But are only interested in value for 'foo' and 'narf', they can still get type hinting/checking/enforcement and the benefits of named mapping. Let's assume the following which has a little bit of context: // developer/consumer code $library = (new SomeLibrary) $library->registerCallback(function ($foo, $narf) {}); $library->call(); // some 3rd party library with a callback system in place class SomeLibrary {
    public function registerCallback(callable $callback) {
      $this->callback = $callback;
    }
    public function call() {
      if (!$this->callback) {
        return;
      }
      $args = [];
      $args['foo'] = 5;
      $args['beep'] = 'value from db';
      $args['narf'] = 'poink';
      $args['boop'] = new StdClass;
      $args['isNoomable'] = false;
      ($this->callback)(...$args);
    }
} This will fail with message: PHP Fatal error: Uncaught Error: Unknown named parameter $beep in ... Currently, the consumer/developer would have to write: $library->registerCallback(function (...$args) {
    $foo = $args['foo'];
    $narf = $args['narf'];
    // ...
}); // or $library->registerCallback(function ($foo, $beep, $narf, $boop, $isNoomable) {
    // do something with foo or narf
}); Additionally, the library/framework is now precluded from adding new parameters since any consuming callables would also have to introduce these new parameters as it could be considered a BC break. The more I think about it though, the more sensible this would be as it allows the callback provider to opt into named parameter mapping destructuring: $library->registerCallback(function (...[string $foo, string $narf]) {
    // do something with $foo and $narf
}); -ralph

Thread (9 messages)

« previous php.internals (#115268) next »