php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #52157 Unwanted call of the magic __get method
Submitted: 2010-06-23 12:43 UTC Modified: 2015-03-25 21:17 UTC
From: l dot declercq at nuxwin dot com Assigned:
Status: Not a bug Package: Scripting Engine problem
PHP Version: 5.2.14RC1 OS: Debian
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: l dot declercq at nuxwin dot com
New email:
PHP Version: OS:

 

 [2010-06-23 12:43 UTC] l dot declercq at nuxwin dot com
Description:
------------
hello everyone ;

In the documentation, it's said that the magic __call method is called when an inaccessible member is read. But I've small issue in my current class with a setter method. When I try to set an Alias on an inexistent member, the magic __call method is also called.

To solve the problem, I uses a workaround like this in the setter method:

public static function &setAlias($index, &$value) {

	$instance = self::getInstance();
	// Small workaround to avoid call of magic __get().
	$instance->$index = '';

	return $instance->$index = &$value;
}

Strange behavior, no ? It's bug or not, if not, can you explain to me the reason of this statement ? I uses php 5.2.6.

Sorry, for my poor english, I'm french.

Test script:
---------------
class Registry {

	protected static $_instance = null;

	public static function getInstance() {

		if(self::$_instance == null) {
			self::$_instance = new self;
		}

		return self::$_instance;
	}

	public function __get($index) {

		print 'Oh my god...';
	}

	public static function &setAlias($index, &$value) {

		$instance = self::getInstance();
		return $instance->$index = &$value;
	}
}

class myObject {

	protected static $_instance = null;

	public static function &getInstance() {

		if(self::$_instance == null) {
			self::$_instance = new self();
		}

		return  self::$_instance;
	}

}

// Here, I want register a `myObject` instance by reference (not by object identifier)
Registry::setAlias('MyData', myObject::getInstance());

echo '<pre>';
	var_dump(Registry::getInstance());
echo '</pre>';


Expected result:
----------------
object(Registry)#2 (1) {
  ["MyData"]=>
  &object(myObject)#1 (0) {
  }
}


Actual result:
--------------
Oh my god... Notice: Indirect modification of overloaded property Registry::$MyData has no effect in /var/www/test.php on line 67 Fatal error: Cannot assign by reference to overloaded object in /var/www/test.php on line 67 

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2010-06-23 13:50 UTC] felipe@php.net
-Summary: Unwanted call of the magic __call method +Summary: Unwanted call of the magic __get method -Package: *General Issues +Package: Scripting Engine problem
 [2010-06-23 18:07 UTC] l dot declercq at nuxwin dot com
oops, sorry, it's the magic __get() methods that is unwanted here, not the magic __call() method ..
 [2010-09-18 05:38 UTC] mail_ben_schmidt at yahoo dot com dot au
You are trying to do something not supported by PHP. The key is in your final error: Cannot assign by reference to overloaded object.

The way assign-by-reference works is that it gets a reference to the left-hand-side of the assignment, and then changes that to be a reference to the right hand side. So it is no surprise that __get() is called. However, PHP does not support returning a reference from __get() and assigning to that reference. This feature would need to be added to PHP for it to work, and it is not a simple task, because __get() needs to be able to work for non-references; it would probably require a new magic method for assign-by-reference, &__getReference($index) or something like that.

I assume your intention is that it behave the same way as it would behave if you did not have a __get() method. In this case, I suggest you do an assignment by value (of anything!) and then assign by reference to the now-existing property:

public static function &setAlias($index, &$value) {
	$instance = self::getInstance();
	// Create the property if it doesn't exist
	if (!isset($instance->$index)) $instance->$index = true;
	// Set it by reference
	return $instance->$index = &$value;
}

Of course, this will only work if any __isset() method does what is sensible, and any __set() method actually does create the member $index.
 [2015-03-25 21:17 UTC] cmb@php.net
-Status: Open +Status: Not a bug
 [2015-03-25 21:17 UTC] cmb@php.net
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php


 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Sun Jul 13 21:01:33 2025 UTC