[#3]
willbrownsberger at gmail dot com [2015-09-03 01:20:54]
Just wanted to share a trap for the unwary. Where there are several layers of object assignments, setting the bottom object's properties as private will prevent its exposure. However, if the bottom object has public properties, intermediate objects which are themselves set as private but are derived from the bottom object can inadvertently be exposed to updates.
This follows logically from the reference model in php ( http://php.net/manual/en/language.oop5.references.php ), but can yield a result that is surprising until one gets the reference model. The following example demonstrates the phenomenon.
// underlying class for offering database results to other objects
// __construct method yields public results -- bottom object in example
class database_result {
public $column1;
public function __construct() {
// . . . database access . . .
$this->column1 = 'foo';
}
}
// application dictionary accesses database and caches results
// for application objects -- this is the second layer in the example
class dictionary {
private $reference_object;
public function __construct (){
$this->reference_object = new database_result;
}
public function get_reference_object() {
return ( $this->reference_object );
}
}
$dictionary = new dictionary;
$pointer_to_dictionary = $dictionary;
// now set up a client class that will use a working copy of the dictionary -- this is the third layer in the example
class dictionary_user {
private $pointer_to_dictionary;
public function __construct () {
global $dictionary;
// $this->pointer_to_dictionary = $dictionary->reference_object;
// Fatal error: Cannot access private property dictionary::$reference_object in /var/www/html/index.php . . .
// still cannot directly access dictionary properties even in this context, except through getter
$this->pointer_to_dictionary = $dictionary->get_reference_object();
}
// however, can now operate on dictionary through the pointer
public function set_pointer_to_dictionary ( $value ) {
$this->pointer_to_dictionary->column1 = $value;
}
public function get_pointer_to_reference_object(){
return ($this->pointer_to_dictionary);
}
}
$dictionary_user = new dictionary_user;
$dictionary_user->set_pointer_to_dictionary ( 'foochanged' );
echo ('
');
var_dump ( $dictionary_user->get_pointer_to_reference_object()); echo '
';
// object(database_result)#2 (1) { ["column1"]=> string(10) "foochanged" } -- of course, the user object is changed
var_dump ( $dictionary->get_reference_object() );
// object(database_result)#2 (1) { ["column1"]=> string(10) "foochanged" } -- however, the private dictionary object is also now corrupted!
// Note: If the underlying database result object $column1 as private, this will cause set_pointer_to_dictionary to generate the usual fatal error
// but making the bottom object private may defeat its purpose of exposing results.