RE: [PHP] Magic Methods not working
| From: | Daevid Vincent | Date: | Wed, 27 Jan 2010 03:21:34 +0000 |
| Subject: | RE: [PHP] Magic Methods not working | ||
| References: | 1 | Groups: | php.general |
| Request: | Send a blank email to php-general+get-301520@lists.php.net to get a copy of this message | ||
> -----Original Message-----
> From: Paul M Foster [mailto:paulf@quillandmouse.com]
> Sent: Tuesday, January 26, 2010 7:05 PM
> To: php-general@lists.php.net
> Subject: [PHP] Magic Methods not working
>
> I have a class which instantiates other classes, and has a
> magic method
> like this:
>
> function _get($classname)
> {
> return $this->instantiate($classname);
> }
>
> Obviously, the class also has an instantiate method which does what it
> says.
>
> Here's the problem: When I call the instantiate method, it works fine,
> like this:
>
> $db = $sc->instantiate('database');
>
> But when I do the following, it *doesn't* work:
>
> $db = $sc->database;
>
> In fact it does not call the instantiate() method; I've placed a print
> statement in the instantiate() method which fires at then end of the
> routine. That statement doesn't fire with the above code.
>
> The docs on magic methods are pretty slim, so I'm not sure what it is
> I'm missing. Can someone enlighten me?
>
> Paul
http://us2.php.net/manual/en/language.oop5.magic.php
There are TWO underscores needed, not one.
__get()
Also, just to save you some time/grief, you might consider using my awesome
routines:
Put these in your base.class.php and extend it for all other classes.
Magic.
/**
* Provides generic getters and setters
*
* @access public
* @param string $method The method name.
* @param array $arguments The arguments passed to the method.
* @return mixed
* @author Daevid Vincent [daevid@daevid.com]
* @date 02/02/09
* @see __get(), __set()
*/
public function __call( $method, $arguments )
{
$prefix = strtolower( substr( $method, 0, 3 ) );
$property = strtolower( substr( $method, 4 ) );
if ( empty($prefix) || empty($property) ) return;
//exit("__call($method) :: prefix='$prefix' and
property='$property'");
if ( 'get' == $prefix )
{
if ( property_exists($this, $property) )
return $this->$property;
else
return $this->__get($property);
}
elseif ( 'set' == $prefix )
{
if ( property_exists($this, $property) )
return $this->$property = $arguments[0];
else
return $this->__set($property, $arguments[0]);
}
// Technically we should never get to this point as most calls are
get_() or set_()
echo "<p><font color='#ff0000'>Attempted to
'".$prefix."->".$method."()' in class
'".$this->get_class_name()."'.</font><p>\n";
backtrace();
}
/**
* magic function to handle any accessing of undefined variables.
* Since PHP is "lax" this will help prevent stupid mistakes.
*
* @access public
* @return void
* @param mixed $property name of the variable
* @author Daevid Vincent [daevid@daevid.com]
* @date 05/14/09
* @see __set(), __call()
*/
public function __get($property)
{
if ($_SESSION['DEVELOPMENT'] && !$_SESSION['mobile'])
{
echo "<p><font color='#ff0000'>Attempted to __get()
non-existant property/variable '".$property."' in class
'".$this->get_class_name()."'.</font><p>\n";
$this->suggest_alternative($property);
backtrace();
exit;
}
else exit("__get($property) NO SUCH PROPERTY IN
".$this->get_class_name().' CLASS');
//Throw new BadProperty($this, 'get', $property);
}
/**
* magic function to handle any setting of undefined variables.
* Since PHP is "lax" this will help prevent stupid mistakes.
*
* @access public
* @return void
* @param mixed $property name of the variable
* @param mixed $val value of the variable
* @author Daevid Vincent [daevid@daevid.com]
* @date 05/14/09
* @see __get(), __call()
*/
public function __set($property, $val)
{
if ($_SESSION['DEVELOPMENT'] && !$_SESSION['mobile'])
{
echo "<p><font color='#ff0000'>Attempted to __set()
non-existant property/variable '".$property."' to '".$val."'
in class
'".$this->get_class_name()."'.</font><p>\n";
$this->suggest_alternative($property);
backtrace();
exit;
}
else exit("__set($property) NO SUCH PROPERTY IN
".$this->get_class_name().' CLASS');
//Throw new BadProperty($this, 'set', $property);
}
/**
* Suggests alternative properties should a __get() or __set() fail
*
* @param string $property
* @return string
* @author Daevid Vincent [daevid@daevid.com]
* @date 05/19/09
* @see __get(), __set(), __call()
*/
public function suggest_alternative($property)
{
$parts = explode('_',$property);
foreach($parts as $i => $p) if ( in_array($p,
array('_','id','get','set')) ) unset($parts[$i]);
echo 'checking for <b>'.implode(' or ',$parts)."</b> and
suggesting
the following:<br/>\n";
foreach($this as $key => $value)
foreach($parts as $p)
if (stripos($key, $p) !== false)
{
if ($property == 'get_'.$p || $property ==
'set_'.$p)
$possibilities[] =
'<li>'.$key."<b>()</b> <i>note the
parenthesis</i></li>";
else
$possibilities[] =
'<li>'.$key."</li>";
}
echo
"<ul>\n".implode("\n",array_unique($possibilities))."</ul>\n";
//[dv] unfortunately there doesn't seem to be a way to know if
someone called this as a method () or directly :(
//if ( strpos($property, '()') === false )
if (count($parts) == 1 && $property == 'get_'.$parts[0] ||
$property == 'set_'.$parts[0])
echo 'Perhaps you forgot the parenthesis at the end of the
method call, and meant this instead: <b>'.$property.'()</b>';
}