Mat
Aktives Mitglied
PHP hat ja jetzt auch die Pfeilschreibweise für Closures/Anonyme Funktionen, was zu vermehrtem Gebrauch einlädt. Ich dachte mir direkt: oha, da muss ich bei großen Schleifen ja aufpassen, dass ich nicht die Erzeugung von Closures spamme.
Hab es kurz getestet:
"Was? Die Closures werden wiederverwendet? Das ist ja voll gut.", dachte ich mir zuerst. Aber das kam mir irgendwie verdächtig vor. Deswegen ein zweiter Test:
Sehe ich das richtig, dass das einfach nur aggressive Garbage Collection ist, die sogar die Erinnerung an die Ids löscht? Das ist ja brutal und erinnert an https://de.wikipedia.org/wiki/Damnatio_memoriae , aber wie auch im alten Ägypten kann das doch nicht sehr performant sein.
Hab es kurz getestet:
Test 1: Recycling? Nein? Doch! Oh!
Test1:
<?php
// playground.php
function test()
{
$nums = [1, 2, 3, 4, 5];
$sum = 0;
for ($i = 0; $i < count($nums); $i++) {
$closure = fn($x, $y) => $x + $y;
$sum = $closure($sum, $nums[$i]);
$closureId = spl_object_id($closure);
echo "Iteration $i: Closure ID = {$closureId}\n";
/*
Was? Recycling? Ui
Iteration 0: Closure ID = 1
Iteration 1: Closure ID = 2
Iteration 2: Closure ID = 1
Iteration 3: Closure ID = 2
Iteration 4: Closure ID = 1
*/
}
}
test();
$closure = fn($x, $y) => $x + $y;
$closureId = spl_object_id($closure);
echo "Neue Closure - ID: {$closureId}\n"; // => Neue Closure - ID: 1
$closure = fn($x, $y) => $x + $y;
$closureId = spl_object_id($closure);
echo "Neue Closure - ID: {$closureId}\n"; // => Neue Closure - ID: 2
$closure = fn($x, $y) => $x + $y;
$closureId = spl_object_id($closure);
echo "Neue Closure - ID: {$closureId}\n"; // => Neue Closure - ID: 1
"Was? Die Closures werden wiederverwendet? Das ist ja voll gut.", dachte ich mir zuerst. Aber das kam mir irgendwie verdächtig vor. Deswegen ein zweiter Test:
Test2: Wenn die Müllabfuhr n mal klingelt
test2 und Ergebnisse in Kommentaren:
<?php
function test2()
{
$closures = new WeakMap(); // verhindert kein GC
$ids = [];
foreach (range(1, 3) as $i) {
$closure = fn($x, $y) => $x + $y;
$id = spl_object_id($closure);
$ids[] = $id; // ids retten
$closures[$closure] = "Iteration $i: ID: $id";
}
print_r($closures);
print_r($ids);
/*
Sieht nur aus wie Recycling und ist eigentlich GC und ID-Recycling?
WeakMap Object
(
[0] => Array
(
[key] => Closure Object
(
[parameter] => Array
(
[$x] => <required>
[$y] => <required>
)
)
[value] => Iteration 3: ID: 2
)
)
Array
(
[0] => 2
[1] => 3
[2] => 2
)
*/
echo "--- test2() FERTIG ---\n";
return [$closures, $ids];
}
$results = test2();
echo "--- RÜCKGABEWERTE VON test2() ---\n";
print_r($results);
/*
GC nach Verlassen des Scopes immerhin wie erwartet
Array
(
[0] => WeakMap Object
(
)
[1] => Array
(
[0] => 2
[1] => 3
[2] => 2
)
)
*/
echo "--- Global Scope: WeakMap ---\n";
$closures = new WeakMap();
$closure = fn($x, $y) => $x + $y;
$id = spl_object_id($closure);
$closures[$closure] = "1, ID: $id";
$closure = fn($x, $y) => $x + $y;
$id = spl_object_id($closure);
$closures[$closure] = "2, ID: $id";
$closure = fn($x, $y) => $x + $y;
$id = spl_object_id($closure);
$closures[$closure] = "3, ID: $id";
print_r($closures);
/*
das gleiche Verhalten, wie innerhalb von test2()
*/
echo "--- Global Scope: array ---\n";
$closures = []; // Objekte bleiben am Leben, solange container lebt
$closure = fn($x, $y) => $x + $y;
$id = spl_object_id($closure);
$closures["$id"] = $closure;
$closure = fn($x, $y) => $x + $y;
$id = spl_object_id($closure);
$closures["$id"] = $closure;
$closure = fn($x, $y) => $x + $y;
$id = spl_object_id($closure);
$closures["$id"] = $closure;
var_dump($closures);
/*
Das sieht nicht nach Recycling aus, jedes Mal eine neue Closure
array(3) {
[2] =>
class Closure#2 (1) {
public $parameter =>
array(2) {
'$x' =>
string(10) "<required>"
'$y' =>
string(10) "<required>"
}
}
[3] =>
class Closure#3 (1) {
public $parameter =>
array(2) {
'$x' =>
string(10) "<required>"
'$y' =>
string(10) "<required>"
}
}
[4] =>
class Closure#4 (1) {
public $parameter =>
array(2) {
'$x' =>
string(10) "<required>"
'$y' =>
string(10) "<required>"
}
}
}
*/
Sehe ich das richtig, dass das einfach nur aggressive Garbage Collection ist, die sogar die Erinnerung an die Ids löscht? Das ist ja brutal und erinnert an https://de.wikipedia.org/wiki/Damnatio_memoriae , aber wie auch im alten Ägypten kann das doch nicht sehr performant sein.