PHP: Don’t do that

Mein Versuch, mit PHP4 so etwas ähnliches wie Java-Inspection zu realisieren, zeigte beim Update auf von PHP 4.3.1 auf PHP 4.4.0 schwächen: Die beiden Versionen verhalten sich nämlich in Bezug auf References etwas anders, nachdem in der 4.4.0 ein diesbezügliches Sicherheitsloch gestopft wurde.

Wenn man nämlich eine Referenz auf eine Instanzvariable einer Klasse außerhalb der Klasse selbst anlegt und dieser Referenz dann das Ergebnis eines Methodenaufrufes aus der selben Klasse per Reference zuweist, obwohl die aufgerufene Methode ihren Rückgabewert gar nicht by reference zurückgibt, dann verhalten sich die Versionen unterschiedlich (siehe Democode).

Ziel des Programms war es, einen bunt gemischten Baum aus PHP-Arrays und Obejkten dynamisch zu durchlaufen. Der Workaround (wenn man sowas schlimmes wirklich, wirklich machen will, funktioniert über die Einführung einer zusätzlichen temporären Variable, ein unset() auf die Referenzvariable. Danach kann man der Referenzvariable (im Beispiel $c) dann by reference den Wert der temporären Variable zuweisen.

Aber da PHP in diesem Falle sogar eine Notice ausgibt, sollte man solche Spielchen wohl gar nicht erst anfangen und nach einer Besseren Lösung für solche Probleme suchen…

PHP4 changed its behaviour from 4.3.1 to 4.4.0 regarding the way it handles complex situations involving references. This is not documented and PHP issues a notice („Only variables should be assigned by reference“), so you should probably not do this anyway :)

The rationale behind the demo code below that I wrote to reproduce the problem was to built a tree of arbitrary PHP variables (scalars, arrays, objects) where you could call methods of objects somewhere in the tree. I wanted to be able to operate on their return values like further walking down the tree. But since you can not see if a method passes its return value by value or by reference, I don’t see any way to avoid the above notice.


<?php
error_reporting(E_ALL);

header('Content-Type: text/plain');

$myBar = new bar();
// Get an instance of class foo by reference.
$c =& $myBar->getMyFoo();

// Create a reference to that instance of class foo.
$retTwo =& $c;

// Assign by reference. Note that the method does not return
// by reference.
$c =& $c->getInt();

// Prints "int(23)" with both versions.
var_dump($c);

// Prints "object(foo)(0) {}" in 4.3.1, "int(23)" in 4.4.0.
var_dump($myBar->myFoo);

// A simple class with just one method.
class foo{
// Returns by value
function getInt(){
$myInt = 23;
return $myInt;amp;
}
}

// A class containing an instance of class foo.
// There is a method to return that instance by refernce
class bar{
var $myFoo;
function bar(){
$this->myFoo = new foo();
}

function &getMyFoo(){
return $this->myFoo;
}
}
?>

Einen Kommentar schreiben