| Subject | Details |
| :------------- | :---------------------------------------------------------------------------- |
| Plugin | Php Inspections (EA Ultimate), 3.0.2 |
| Language level | PHP 7.3 |
I question that suggesting a move to static closures is a good idea. I set up a test script to compare the same anonymous function, one using static and one not static, and every time I run it, the static either makes no difference what so ever, or worse it actually slows down the call.
Script:
define('LOOP', 9999999);
function f1() {
$array = ['b', 'c', 'a'];
for ($i = 0; $i < LOOP; ++$i) {
// sort monitors alphabetically by their names
uasort($array, function ($a, $b) {
if ($a === $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
});
}
}
function f2() {
$array = ['b', 'c', 'a'];
for ($i = 0; $i < LOOP; ++$i) {
// sort monitors alphabetically by their names
uasort($array, static function ($a, $b) {
if ($a === $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
});
}
}
for ($i = 0; $i < 20; $i++) {
$time1sum = 0;
$time2sum = 0;
$start = microtime(true);
f1();
$stop = microtime(true);
$time1 = $stop - $start;
$time1sum += $time1;
$start = microtime(true);
f2();
$stop = microtime(true);
$time2 = $stop - $start;
$time2sum += $time2;
echo $time1 . "\t";
echo $time2 . "\t";
echo 'Non static to static difference: ' . round(($time1 - $time2) / $time2, 2) * 100 . ' %' . "\n";
}
echo "\n" . 'All tests average non static to static difference: ' . round(($time1sum - $time2sum) / $time2sum, 2) * 100 . ' %' . "\n";
I ran the above with 10 loops and got negative results, and then ran it with 20 loops and got the same.
Results:
"C:\Program Files\PHP\7.3\php.exe" foo . php
3.3828949928284 3.3860850334167 Non static to static difference: -0 %
3.3236382007599 3.4230880737305 Non static to static difference: -3 %
3.3295810222626 3.4709639549255 Non static to static difference: -4 %
3.5906729698181 4.3166460990906 Non static to static difference: -17 %
3.532016992569 3.3007140159607 Non static to static difference: 7 %
3.3016149997711 3.1723878383636 Non static to static difference: 4 %
3.176647901535 3.1846690177917 Non static to static difference: -0 %
3.1621389389038 3.1926288604736 Non static to static difference: -1 %
3.5156707763672 3.5725631713867 Non static to static difference: -2 %
3.2713830471039 3.3552980422974 Non static to static difference: -3 %
All tests average non static to static difference: -3 %
"C:\Program Files\PHP\7.3\php.exe" foo . php
3.2651560306549 3.7372040748596 Non static to static difference: -13 %
3.5707740783691 3.1998999118805 Non static to static difference: 12 %
3.6920659542084 3.4780099391937 Non static to static difference: 6 %
3.3633909225464 3.1590549945831 Non static to static difference: 6 %
3.1764988899231 3.1446340084076 Non static to static difference: 1 %
3.6400108337402 3.9502489566803 Non static to static difference: -8 %
3.1750378608704 3.2438368797302 Non static to static difference: -2 %
3.5191330909729 3.1702718734741 Non static to static difference: 11 %
3.1807131767273 3.1765840053558 Non static to static difference: 0 %
3.1785180568695 3.1750609874725 Non static to static difference: 0 %
All tests average non static to static difference: 0 %
"C:\Program Files\PHP\7.3\php.exe" foo . php
3.4312839508057 3.2204990386963 Non static to static difference: 7 %
3.2184920310974 3.2088260650635 Non static to static difference: 0 %
3.2450928688049 3.794802904129 Non static to static difference: -14 %
3.4523038864136 3.4881701469421 Non static to static difference: -1 %
4.0035569667816 3.3903529644012 Non static to static difference: 18 %
3.2574179172516 3.2170910835266 Non static to static difference: 1 %
3.5720570087433 3.351634979248 Non static to static difference: 7 %
3.5094299316406 3.5594971179962 Non static to static difference: -1 %
3.4494309425354 3.4567530155182 Non static to static difference: -0 %
3.2775058746338 3.5631980895996 Non static to static difference: -8 %
3.4885699748993 3.2566659450531 Non static to static difference: 7 %
3.3013529777527 3.3204050064087 Non static to static difference: -1 %
3.8423149585724 3.2486469745636 Non static to static difference: 18 %
3.3160519599915 3.288556098938 Non static to static difference: 1 %
3.4402360916138 3.3753988742828 Non static to static difference: 2 %
3.2076458930969 3.3102099895477 Non static to static difference: -3 %
3.2257452011108 3.4204609394073 Non static to static difference: -6 %
3.6831171512604 3.3374209403992 Non static to static difference: 10 %
3.2807421684265 3.217159986496 Non static to static difference: 2 %
3.2188529968262 3.2173728942871 Non static to static difference: 0 %
All tests average non static to static difference: 0 %
Process finished with exit code 0
"C:\Program Files\PHP\7.3\php.exe" E:\sentientData\websites\sentient\web\finances . rollforward\foo . php
3.2186758518219 3.5638139247894 Non static to static difference: -10 %
3.4221830368042 3.4193480014801 Non static to static difference: 0 %
3.1657350063324 3.178699016571 Non static to static difference: -0 %
3.1883678436279 3.1919031143188 Non static to static difference: -0 %
3.1611869335175 3.2072789669037 Non static to static difference: -1 %
3.3773889541626 3.5609378814697 Non static to static difference: -5 %
3.3321788311005 3.2463641166687 Non static to static difference: 3 %
3.1810870170593 3.1919810771942 Non static to static difference: -0 %
3.1960289478302 3.1950898170471 Non static to static difference: 0 %
3.2791910171509 3.2046940326691 Non static to static difference: 2 %
3.3247151374817 3.7156910896301 Non static to static difference: -11 %
3.2100920677185 3.1687409877777 Non static to static difference: 1 %
3.3439400196075 3.1974020004272 Non static to static difference: 5 %
3.1860420703888 3.1946129798889 Non static to static difference: -0 %
3.1718430519104 3.1996901035309 Non static to static difference: -1 %
3.3595550060272 3.3226308822632 Non static to static difference: 1 %
3.1817259788513 3.2180700302124 Non static to static difference: -1 %
3.167268037796 3.1873691082001 Non static to static difference: -1 %
3.1867201328278 3.1929550170898 Non static to static difference: -0 %
3.1829781532288 3.2076261043549 Non static to static difference: -1 %
All tests average non static to static difference: -1 %
The URL provided in tooltip that pops up directly references hydration as the point where a 15% performance boost was observed. Perhaps it's just their specific use case that produces an improvement?
Any thoughts?
Your test is broken because the sums are reset in the loop, and displayed outside the loop.
Hence sums will always be the last iteration result.
Very well spotted but also very easy to correct for. If you manually add up the numbers you get
-19
13
39
-17
Which still leaves the variance in performance I describe, and still makes this "optimisation" questionable.
Fix with four runs:
<?php
define('LOOP', 9999999);
class foo {
public function f1(): void {
$array = ['b', 'c', 'a'];
for ($i = 0; $i < LOOP; ++$i) {
// sort monitors alphabetically by their names
uasort($array, function ($a, $b) {
if ($a === $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
});
}
}
private function f2(): void {
$array = ['b', 'c', 'a'];
for ($i = 0; $i < LOOP; ++$i) {
// sort monitors alphabetically by their names
uasort($array, static function ($a, $b) {
if ($a === $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
});
}
}
public function run(): void {
$time1sum = 0;
$time2sum = 0;
for ($i = 0; $i < 20; $i++) {
$start = microtime(true);
$this->f1();
$stop = microtime(true);
$time1 = $stop - $start;
$time1sum += $time1;
$start = microtime(true);
$this->f2();
$stop = microtime(true);
$time2 = $stop - $start;
$time2sum += $time2;
echo $time1 . "\t";
echo $time2 . "\t";
echo 'Non static to static difference: ' . round(($time1 - $time2) / $time2, 2) * 100 . ' %' . "\n";
}
echo "\n" . 'All tests average non static to static difference: ' . round(($time1sum - $time2sum) / $time2sum, 2) * 100 . ' %' . "\n";
}
}
$foo = new foo();
$foo->run();
Runs:
"C:\Program Files\PHP\7.3\php.exe" foo.php
3.5600728988647 3.2204239368439 Non static to static difference: 11 %
3.6837649345398 3.3336009979248 Non static to static difference: 11 %
3.218405008316 3.4317600727081 Non static to static difference: -6 %
3.8198270797729 3.5858960151672 Non static to static difference: 7 %
3.7928111553192 3.3903489112854 Non static to static difference: 12 %
3.2252900600433 3.3361229896545 Non static to static difference: -3 %
3.1695611476898 3.4329369068146 Non static to static difference: -8 %
3.5641338825226 3.4307041168213 Non static to static difference: 4 %
3.683650970459 3.4104731082916 Non static to static difference: 8 %
3.2660989761353 3.3289551734924 Non static to static difference: -2 %
3.3522641658783 4.2610330581665 Non static to static difference: -21 %
3.2521572113037 3.1892178058624 Non static to static difference: 2 %
3.2665319442749 3.2972049713135 Non static to static difference: -1 %
3.1971127986908 3.2139241695404 Non static to static difference: -1 %
3.1498980522156 3.1724209785461 Non static to static difference: -1 %
3.2948110103607 4.2348690032959 Non static to static difference: -22 %
4.3396060466766 4.2737739086151 Non static to static difference: 2 %
3.497129201889 3.3370578289032 Non static to static difference: 5 %
3.1421558856964 3.2606620788574 Non static to static difference: -4 %
3.2239878177643 3.191116809845 Non static to static difference: 1 %
All tests average non static to static difference: -1 %
"C:\Program Files\PHP\7.3\php.exe" foo.php
3.3130989074707 3.1858880519867 Non static to static difference: 4 %
3.1626861095428 3.1706159114838 Non static to static difference: -0 %
3.2909832000732 3.1377539634705 Non static to static difference: 5 %
3.1494040489197 3.1701090335846 Non static to static difference: -1 %
3.156448841095 3.1420698165894 Non static to static difference: 0 %
3.1930341720581 3.131306886673 Non static to static difference: 2 %
3.1356887817383 3.1895928382874 Non static to static difference: -2 %
3.1410310268402 3.1395659446716 Non static to static difference: 0 %
3.1745209693909 3.159236907959 Non static to static difference: 0 %
3.1534721851349 3.2909059524536 Non static to static difference: -4 %
3.3085238933563 3.2688660621643 Non static to static difference: 1 %
3.3323731422424 3.2943608760834 Non static to static difference: 1 %
3.1350820064545 3.1734299659729 Non static to static difference: -1 %
3.3568239212036 3.2053000926971 Non static to static difference: 5 %
3.1823420524597 3.1383790969849 Non static to static difference: 1 %
3.2001509666443 3.2830550670624 Non static to static difference: -3 %
3.141585111618 3.153342962265 Non static to static difference: -0 %
3.1806190013885 3.1352331638336 Non static to static difference: 1 %
3.1511831283569 3.2001218795776 Non static to static difference: -2 %
3.157653093338 3.1504058837891 Non static to static difference: 0 %
All tests average non static to static difference: 0 %
"C:\Program Files\PHP\7.3\php.exe" foo.php
3.1469099521637 3.2171349525452 Non static to static difference: -2 %
3.379508972168 3.4048669338226 Non static to static difference: -1 %
3.5419409275055 3.7595450878143 Non static to static difference: -6 %
3.1761751174927 3.2062270641327 Non static to static difference: -1 %
3.2597951889038 3.2594339847565 Non static to static difference: 0 %
3.1624429225922 3.2813491821289 Non static to static difference: -4 %
3.1844379901886 3.1396811008453 Non static to static difference: 1 %
3.1595251560211 3.1598010063171 Non static to static difference: -0 %
3.1434550285339 3.1402409076691 Non static to static difference: 0 %
3.1460239887238 3.1673510074615 Non static to static difference: -1 %
3.164391040802 3.431333065033 Non static to static difference: -8 %
3.4538049697876 3.4072041511536 Non static to static difference: 1 %
3.8513739109039 3.1776728630066 Non static to static difference: 21 %
3.1819241046906 3.2077550888062 Non static to static difference: -1 %
3.1560790538788 3.6280858516693 Non static to static difference: -13 %
3.7892851829529 3.160031080246 Non static to static difference: 20 %
3.1639399528503 3.2132639884949 Non static to static difference: -2 %
3.1559450626373 3.1600840091705 Non static to static difference: -0 %
3.1343491077423 3.161857843399 Non static to static difference: -1 %
3.3149309158325 3.1707730293274 Non static to static difference: 5 %
All tests average non static to static difference: 0 %
"C:\Program Files\PHP\7.3\php.exe" foo.php
3.1415500640869 3.1424460411072 Non static to static difference: -0 %
3.1412000656128 3.1338069438934 Non static to static difference: 0 %
3.1545009613037 3.1280500888824 Non static to static difference: 1 %
3.2754538059235 3.1379261016846 Non static to static difference: 4 %
3.1467850208282 3.1489191055298 Non static to static difference: -0 %
3.1375751495361 3.1211009025574 Non static to static difference: 1 %
3.1798250675201 3.1289689540863 Non static to static difference: 2 %
3.1467831134796 3.1584830284119 Non static to static difference: -0 %
3.16565990448 3.1367599964142 Non static to static difference: 1 %
3.2606182098389 3.1503579616547 Non static to static difference: 3 %
3.1827788352966 3.1436688899994 Non static to static difference: 1 %
3.2032339572906 3.2934818267822 Non static to static difference: -3 %
3.6449680328369 3.6569910049438 Non static to static difference: -0 %
3.8245720863342 4.0321309566498 Non static to static difference: -5 %
3.6452209949493 4.2913200855255 Non static to static difference: -15 %
3.4961938858032 3.4603838920593 Non static to static difference: 1 %
3.1877300739288 3.1745159626007 Non static to static difference: 0 %
3.2356557846069 3.200740814209 Non static to static difference: 1 %
3.2313299179077 3.2537350654602 Non static to static difference: -1 %
3.1493818759918 3.1757941246033 Non static to static difference: -1 %
All tests average non static to static difference: -1 %
Post fix declaring the function static provides no benefit what-so-ever, or worse yet degrades performance.
Your test is flawed for few reasons:
Look at this case:
function f1() {
$max = 10000;
$range = range(1,$max);
$temp = [5,8,3,9];
shuffle($range);
$t1 = $range[mt_rand(0,$max-1)];
$t2 = $range[mt_rand(0,$max-1)];
$t3 = $t1**$t2;
return $temp[2];
}
PHP 7.3 will optimize this function to something like
function f1() {
return 3; //value of $temp[2]
}
That's because rest of code doesn't impact the return value. For more details watch talk by Rasmus Lerdorf (creator of PHP) here.
So, I improved your tests a bit by adding more randomness and removing functions, and I see a consistent improvement overall.
For small arrays ($max=10) difference is huge (90% or more on average), for bigger arrays ($max=3000) it's smaller (around 1.5% on average).
So this micro-optimization helps on average, especially for simple functions.
You could check that by using vld to analyze php opcodes to be even more sure, though I don't feel like this is needed.
Here is improved code:
<?php
function test()
{
function randomArr($n)
{
$range = range(1, 50000, mt_rand(1, 10));
shuffle($range);
return array_slice($range, 0, $n);
}
$values = [];
$time1sum = 0;
$time2sum = 0;
$max = 3000;
for ($i = 0; $i < 1000; $i++) {
$array = randomArr($max);
$array2 = $array;
$start = microtime(true);
uasort($array, function ($a, $b) {
if ($a === $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
});
$stop = microtime(true);
$f1 = $array[mt_rand(0, $max - 1)];
$values[] = $f1;
$time1 = $stop - $start;
$time1sum += $time1;
$start = microtime(true);
uasort($array2, static function ($a, $b) {
if ($a === $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
});
$stop = microtime(true);
$f2 = $array2[mt_rand(0, $max - 1)];
$values[] = $f2;
$time2 = $stop - $start;
$time2sum += $time2;
echo $time1 . "\t";
echo $time2 . "\t";
echo 'Non static to static difference: ' . round(($time1 - $time2) / $time2, 4) * 100 . ' %' . "\n";
}
echo "\n" . 'All tests average non static to static difference: ' . round(($time1sum - $time2sum) / $time2sum, 4) * 100 . ' %' . "\n";
return $values;
}
$tmp = test();
echo json_encode($tmp)[300] . PHP_EOL; //just to be sure stuff isn't optimized out
Hi Jacek,
Running the code in a class isn't flaw in the slightest, as the plugin recommends the alteration in that exact scenario. I'll take your test and restructure it and see how I get on.
I based my example on your first test (one in the post).
Running code in class is not a problem, but using static closure is suggested even when code is not in a class. Putting it in a class shouldn't change anything.
Just remember that if you test things like that doing any additional work (calling functions, creating classes etc.) creates overhead and your tests won't show true difference. That's why I removed functions f1 and f2 and moved their code to main loop.
Yes but the point of my post was that this optimisation seems to be an
optimisation only in particular circumstances, so refactoring the test so
as to extract an optimisation furthers my point!
On Mon, 2 Sep 2019 at 08:30, Jacek Andrzejewski notifications@github.com
wrote:
I based my example on your first test (one in the post).
Running code in class is not a problem, but using static closure is
suggested even when code is not in a class. Putting it in a class shouldn't
change anything.Just remember that if you test things like that doing any additional work
(calling functions, creating classes etc.) creates overhead and your tests
won't show true difference. That's why I removed functions f1 and f2 and
moved their code to main loop.—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/kalessil/phpinspectionsea/issues/1385?email_source=notifications&email_token=AAKX7ML3LI2WYHOFHBCPUXDQHS6FPA5CNFSM4IMMQQSKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD5U6YNQ#issuecomment-527035446,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAKX7MKPQMZLYXATKPY6PL3QHS6FPANCNFSM4IMMQQSA
.
It optimizes things always (on average). You can of course get "worse" performance in individual cases (even in tests I wrote), but that's just natural variance.
I checked it also with vld, but in 7.2 and 7.3 OP codes are identical. Maybe this optimization makes bigger sense in pre 7.0.
IMO, it's not an "optimization" (seems like we're about to start a forever lasting debate...)
But it's very useful as a way to avoid using "$this" by mistake inside the callback. The more scoped blocks are, the easier it will be to debug ("oh, it's a static function, so I know everything I need is in the function block and in its use clause" vs "ah, it's a non-static function, so anything in the $this scope could interfere...")
Oh, I totally missed the thread. To not confuse people, I updated message to This closure can be declared as static (better scoping; in some cases can improve performance).
The performance optimization is taking effect only in classes context, and possible due to scoping separation of closure and the class itself (PHP will recognize that closure is not bound to the class and does runtime magic).
The referenced show-case: https://github.com/Ocramius/GeneratedHydrator/releases/tag/3.0.0 is exactly fits to the optimization scenario.
Most helpful comment
Oh, I totally missed the thread. To not confuse people, I updated message to
This closure can be declared as static (better scoping; in some cases can improve performance).The performance optimization is taking effect only in classes context, and possible due to scoping separation of closure and the class itself (PHP will recognize that closure is not bound to the class and does runtime magic).
The referenced show-case: https://github.com/Ocramius/GeneratedHydrator/releases/tag/3.0.0 is exactly fits to the optimization scenario.