Re: Callable arguments cannot have default value

From: Date: Tue, 28 Nov 2023 09:45:43 +0000
Subject: Re: Callable arguments cannot have default value
References: 1  Groups: php.internals 
Request: Send a blank email to internals+get-121819@lists.php.net to get a copy of this message
On Tue, Nov 28, 2023 at 12:59 AM Sergii Shymko <sergey@shymko.net> wrote: > > Hi, > > Wanted to bring up an inconsistent behavior of callable arguments compared to arguments of > other types. > Callable argument cannot have a default value (tested string or array types - both are not > permitted). > The same exact value works perfectly fine when passed dynamically, it just cannot be specified > as a default. > The workaround is to remove the type annotation which is obviously undesirable. > > Here’s an example: > declare(strict_types=1); > function test(callable $idGenerator = 'session_create_id') { > $id = $idGenerator(); > // ... > } > > The function/method declaration above produces the following error on all PHP versions: > Fatal error: Cannot use string as default value for parameter $idGenerator of type callable in > /tmp/preview on line 4 > > Note that the exact same string argument can be passed without any issue: > function test(callable $idGenerator) {…} > test('session_create_id’); > > Is there a specific architectural limitation causing this that's hard/impossible to > overcome? > > I’m aware that class properties cannot be annotated with callable - another unfortunate > limitation. > Callable is not a real type like other primitive types which causes all these inconsistencies, > correct? > Callable properties (separate topic) may be a challenge, but can at least argument defaults be > supported? > > Regards, > Sergii Shymko I stopped using "callable" a long time ago. These days I use \Closure and it works in all the same places (including properties). If you want to accept a callable string, you need to change the type to \Closure|string and verify it with is_callable(). > Is there a specific architectural limitation causing this that's hard/impossible to > overcome? IIRC, default arguments must be compile-time constant, and this isn't, apparently: session_create_id(...) You can also do something like this: function hello() { echo "hi\n"; } class wrapper { public function __construct(public \Closure|string $closure) { is_callable($closure) ?: throw new InvalidArgumentException('closure must be callable'); } public function __invoke() { return ($this->closure)(); } } function test(wrapper|Closure $closure = new wrapper('hello')) { ($closure)(); } test();

« previous php.internals (#121819) next »