6

Basically the purpose of the static keyword is totally clear to me, the PHP docs only explain the purpose of the keyword in the context of classes. I noticed one of my IDE plugins suggesting me that I should declare many of my callback functions as static.

Without static:

$myUniqueArray = unique($arrayToFilter,
    function (ExamQuestion $examQuestion) {
        return $examQuestion->getId();
    }
);

With static:

$myUniqueArray = unique($arrayToFilter,
    static function (ExamQuestion $examQuestion) {
        return $examQuestion->getId();
    }
);

For the result it does not make a difference, it works both. What exactly is the difference between a callback function and a static callback function in PHP under the hood? What are possible benefits and drawbacks in this context?

Blackbam
  • 17,496
  • 26
  • 97
  • 150
  • 2
    I think the answers in [this thread](https://stackoverflow.com/q/19899468/231316) go over several parts of this, including potential performance gains under certain (possibly edge-case) scenarios – Chris Haas Oct 27 '21 at 16:39

2 Answers2

8

You're referring to Static Anonymous Functions [DOC] which are introduced as following in the documentation:

Anonymous functions may be declared statically. This prevents them from having the current class automatically bound to them. Objects may also not be bound to them at runtime.

If you compare that with the explanation of the static keyword in the context of class methods [DOC], this might make the relation more clear. These are introduced as following in the documentation:

Because static methods are callable without an instance of the object created, the pseudo-variable $this is not available inside methods declared as static.

So an actual difference is that you don't have $this bound / available within the anonymous function when it is static.

The reason why you get the suggestion within the IDE is that static anonymous functions give you a slightly better performance over the non-static variant. So unless you need $this within the function, you can safely use the static variant over the non-static one.


Anonymous functions have been introduced in PHP 5.3 [RFC] [5.3.0], with the addition of the static keyword in PHP 5.4.

In PHP 5.3 $this was not automatically bound when defined within a class (intentionally) which has been changed with PHP 5.4 and it is since then that $this is automatically bound for the (non-static) anonymous function.

Since PHP 7.4 you can find arrow functions [DOC] which also come in the static/non-static flavours. However:

Arrow functions support the same features as anonymous functions, except that using variables from the parent scope is always automatic.

It's not only $this that a (non-static) arrow function would bound, it is (even for static ones) that all variables from the parent scope are automatically in use when in use. So this may hit performance more than given the occasional benefit of static for anonymous functions.

NOTE: This is not only theoretical (you need to measure for performance comparisons) but it might also create the impression that all outer scope variables might be bound in the (static) arrow function. But, only those which have a literal variable expression (e.g. $var), not variable variables, not even superglobals but this (which errors in static context and therefore even if it might be bound there as well it would be useless), are available in the arrow function expression. You can safely use static over not using it with arrow functions as well if you're not making use of $this in the arrow function expression (just to make it explicit again with this answer).


As you haven't shared which IDE, it is only a guess to which concrete suggestion you're referring to. Our educated guess is Phpstorm with the EA inspections plugin:

[EA] This closure can be declared as static (better scoping; in some cases can improve performance).

From the Static closures can be used EA inspection. And with the further information:

Analyzes closures and suggests using static closures instead.

This can bring additional performance improvements, e.g. as here:

Also, by using static function () {} closures, we squeezed out another 15% of hydration performance when dealing with private properties.

(from the inspection description provided by Php Inspections ​(EA Ultimate)​ within Phpstorm)

hakre
  • 193,403
  • 52
  • 435
  • 836
  • Regarding the IDE you are totally right yes. Did not recognize this detailed information though, thanks! – Blackbam Oct 27 '21 at 16:54
  • 1
    You can expand the tool-tip and it often shows more information and if even more space is needed for an explanation, it's linked to the EA inspections Github. – hakre Oct 27 '21 at 16:58
  • 1
    Regarding arrow functions, if anything there is a potential performance _cost_ in not having an explicit use clause: the current implementation is fairly "greedy" about what variables it captures. For instance, the following expression captures a copy of `$bigArray`, even though it doesn't need to, because preg_match overwrites it without reading it: `$bigArray=range(1,1_000_000); $string='hello;' $callback = fn() => preg_match('/(l*)/', $string, $bigArray);` – IMSoP Oct 27 '21 at 17:37
  • @IMSoP: Good point, also read that _after_ writing the sentence. I should adopt the wording there. For current PHP there likely is no optimization for arrow functions then. – hakre Oct 27 '21 at 17:43
1

The accpted answer by hakre is very informative but I think it is wrong in one point.

The performance of static arrow functions and static anonymous functions is the same:

This:

$x = 123;
static function () { return true; }

is as performant as this:

$x = 123;
static fn() => true;

The accepted answer assumes that the arrow function is slower because $x is always captured by-value in the arrow function. This is not true because if $x is not used (like in my example) then it is not captured by-value. I tested it by simply using PHP's get_defined_vars().

Michael Käfer
  • 1,597
  • 2
  • 19
  • 37