Introduced in PHP 5.5, it is possible to use the MyClass::class
syntax to reference a class instead of passing it as 'MyClass'
, which is not easily refactorable as it's just a string.
I would very much like to do the same thing with the function name, when passing a callback/callable to call_user_func()
or usort()
.
In the example
usort($files, [FileFunctions::class, 'dircmp']);
only FileFunctions
can easily be refactored.
How can I reference the dircmp
function in a similar way?
Using
usort($a, FileFunctions::dircmp);
leads to a Undefined class constant 'dircmp'
fatal error, as the parameter after the double colons is interpreted as a constant (of course).
<?php
class FileFunctions {
static function dircmp($a, $b) {
if ($a == $b) return 0;
return ($a > $b) ? 1:-1;
}
}
$files = [2,6,1,6,9,2,6,1,7,4];
usort($files, function($a, $b) {return FileFunctions::dircmp($a, $b);});
var_dump($files);
PHPStorm10 correctly refactored dircmp
There are some interesting dicussions regarding this in this reddit thread: https://www.reddit.com/r/PHP/comments/47jxd0/rfc_callable_constructors/d0eip6k
the current syntax for calling dynamically using methods as a callback is rather awful
That seems a difficult problem to solve. People who've looked at it have said that it can't be solved without either merging the symbol tables (which isn't ever likely to happen, as it breaks too much code), or alternatively with a new syntax. One thing that would be possible without clashing with any existing syntax is to use $() to be a language construct of 'give me a callable/closure' of this thing:
$(functionName); // Usable at compile time. $(SomeClass::staticMethodNameAsString); //Usable at compile time $($object->methodName); //Usable at runtime
Without merging the symbol tables, that's almost certainly the cleanest, in the sense of the smallest number of characters, to implement it. I can't see any problems with that (other than it's new syntax which everyone gets scared by), but it's beyond my skills to implement.
and
Props for taking the feedback well. There's definitely need for the problem to be solved in a cleaner way than our current options.
I completely agree that solving the greater callback syntax is very tricky. Even some sort of syntactic sugar that converts a method call into the current array-as-callable could help a lot. The main issue I have with explicitly using strings is that it makes finding call sites of methods drastically harder, both with static analysis and even basic tools like grep. You can't simply
grep -ri -- '->someMethodCall(' *
when it's being invoked with[$obj, 'someMethodCall']
, and looking for the method name without arrows or parens tends to leave a lot of false positives.