Page 1 of 1

__get, interesting problem

Posted: Wed Apr 18, 2007 1:54 pm
by jwalsh
Hey guys,

I got an interesting result by using a magic getter on my class.

Code: Select all

public function __get($Name)
	{
		$getter='get'.$Name;
		
		if(method_exists($this,$getter))
		{
			$returnValue = $this->$getter();
		}
		else
		{
			throw new InvalidPropertyException("No Readable Property: $Name", get_class($this), $Name);
		}
		
		return $returnValue;
	}
And from outside the class...

Code: Select all

$tempProperty = $Class->Property;

if (isset($tempProperty))
{
    echo "GOT HERE";
}
... works properly, and echo's the text. However, this doesn't work...

Code: Select all

if (isset($Class->Property))
{
    echo "GOT HERE";
}
Any ideas?

Posted: Wed Apr 18, 2007 2:49 pm
by volka
You need to overload __isset() as well
http://de3.php.net/manual/en/language.oop5.overloading.php wrote:Since PHP 5.1.0 it is also possible to overload the isset() and unset() functions via the __isset and __unset methods respectively. Method __isset is called also with empty().

Posted: Wed Apr 18, 2007 2:52 pm
by RobertGonzalez
What is the visibility of the property?

Posted: Wed Apr 18, 2007 2:57 pm
by jwalsh
volka wrote:You need to overload __isset() as well
http://de3.php.net/manual/en/language.oop5.overloading.php wrote:Since PHP 5.1.0 it is also possible to overload the isset() and unset() functions via the __isset and __unset methods respectively. Method __isset is called also with empty().
Ok... but what would I do differently? All I want to know is if it has a value or not.

Posted: Wed Apr 18, 2007 2:57 pm
by jwalsh
Everah wrote:What is the visibility of the property?
__Get calls a public function getPropertyName();

Posted: Wed Apr 18, 2007 3:14 pm
by John Cartwright
jwalsh wrote:
volka wrote:You need to overload __isset() as well
http://de3.php.net/manual/en/language.oop5.overloading.php wrote:Since PHP 5.1.0 it is also possible to overload the isset() and unset() functions via the __isset and __unset methods respectively. Method __isset is called also with empty().
Ok... but what would I do differently? All I want to know is if it has a value or not.
Volka's last post told you exactly what you need to do ;)

Posted: Wed Apr 18, 2007 3:30 pm
by jwalsh
Ok. Now I am confused lol, sorry if I'm missing something obvious here.

isset() natively tells me if the parameter exists or not. That's exactly what I want it to do. Unless I'm missing something here, I need to overload isset() to do exactly the same thing it's native function does?

Code: Select all

public function __isset($Value)
{
    return isset($Value);
}

Posted: Wed Apr 18, 2007 5:07 pm
by Weirdan
__isset accepts property name:

Code: Select all

class Tst {
  private $_something;
  public function __isset($name) {
    return isset($this->{'_' . $name});
  }
}
$obj = new Tst;
var_dump(isset($obj->something));

Posted: Thu Apr 19, 2007 9:16 am
by jwalsh
Ok,

I did a little bit more reading on the __isset(), as as I understand the native isset() function doesn't call the magic getter functions.

So, I've put a test case together, and confirmed that my problem still exists, even with the overloaded __isset();

Code: Select all

class Test
{
	public function __get($Name)
	{
		$getter='get'.$Name;
		
		if(method_exists($this,$getter))
		{
			$returnValue = $this->$getter();
		}
		else
		{
			throw new InvalidPropertyException("No Readable Property: $Name", get_class($this), $Name);
		}
		
		return $returnValue;
	}
	
	public function __isset($Property)
	{
		$getter='get'.$Name;
		
		if(method_exists($this,$getter))
		{
			$tempValue = $this->$getter();
			$returnValue = isset($tempValue);
		}
		else
		{
			$returnValue = false;
		}
		
		return $returnValue;
	}
	
	public function getTestProperty()
	{
		return array(5,4,3);
	}
	
}
The following returns false.

Code: Select all

$foo = new Test;

var_dump(isset($foo->TestProperty));
But, the following returns true:

Code: Select all

$foo = new Test;
$bar = $foo->TestProperty;

var_dump(isset($bar));

Posted: Thu Apr 19, 2007 9:42 am
by volka
Please set error_reporting to E_ALL and either set display_errors On or keep an eye on the logfile.
You will get a Notice: Undefined variable: pointing you to the line that needs a little adjustment.

Posted: Thu Apr 19, 2007 10:20 am
by jwalsh
Thanks everyone. We opted to write a custom is_set() function that returns the opposite of is_null, since is_null works properly with our situation.

Thanks again.

Posted: Thu Apr 19, 2007 10:42 am
by volka
If you had turned error_reporting/display_erros on it would have warned you about the simple error
public function __isset($Property)
{
$getter='get'.$Name;
Developmentsystem => error_reporting=E_ALL => many time-killing problems avoided.

Posted: Thu Apr 19, 2007 11:24 am
by jwalsh
Volka,

Thank you for all your help. I see the typo in there, and actually fixed it. With the error reporting on, I didn't get any messages though. In fact, the _isset() never got called. (tried to die()) on the first line of the __isset() and it never fired. I do have PHP 5.1+.

Regardless, our solution, as "hackish" as it is at the moment will suffice for now. We'll refactor it when we have time to diagnose the full cause of the problem.

Thanks again for all your help. It is appreciated.

Josh

Posted: Thu Apr 19, 2007 11:36 am
by volka
Then I suspect your php installation doesn't meat the requirements for this to work.
What does

Code: Select all

<?php echo phpversion(); ?>
print?

Code: Select all

<?php
class Foo {
	public $publicprop = 1;
	private $privateprop = 1;
	
	private function get_bar() {
		return time();
	}
	
	public function __isset($name) {
		echo "__isset($name) invoked   ";
		return method_exists($this, 'get_'.$name);
	}
}

$foo = new Foo;

var_dump(isset($foo->publicprop));
var_dump(isset($foo->privateprop));
var_dump(isset($foo->bar));
var_dump(isset($foo->xyz));
?>
gives me
bool(true)
__isset(privateprop) invoked bool(false)
__isset(bar) invoked bool(true)
__isset(xyz) invoked bool(false)