I have a project in my mind for quite some time, and it requires me to create dynamic objects.
Usually, casting an array to object does the trick (e.g.: (object)array('test'=>5)
). But sometimes, we still want the magic methods to fire up. For that, I have developed a class.
It supports the magic methods __construct
, __get
, __set
, __isset
and __unset
. This also has a method to check the keys in your object.
class Object {
private $props = array();
private $methods = array(
'__construct'=>null,
'__get'=>null,
'__set'=>null,
'__isset'=>null,
'__unset'=>null
);
private function __run_magic_method( $method, $args=null )
{
$obj = (object)$this->props;
$return = call_user_func_array( $this->methods[$method], array_merge( array(&$obj), (array)$args ) );
$this->props = (array)$obj;
return $return;
}
private function __has_magic_method( $method )
{
return isset( $this->methods[$method] ) && is_callable( $this->methods[$method] );
}
function __construct( array $props )
{
foreach( array_keys($this->methods) as $method )
{
if( isset( $props[$method] ) )
{
$this->methods[$method] = $props[$method];
unset( $props[$method] );
}
}
$this->props = $props;
if( $this->__has_magic_method( '__construct' ) )
{
$this->__run_magic_method( '__construct' );
}
}
function __get( $key )
{
if($this->__has_magic_method('__get' ) )
{
return $this->__run_magic_method( '__get', array($key) );
}
else
{
return $this->props[$key];
}
}
function __set( $key, $value )
{
if( $this->__has_magic_method( '__set' ) )
{
$this->__run_magic_method( '__set', array( $key, $value ) );
}
else
{
$this->props[$key] = $value;
}
}
function __isset( $key )
{
if( $this->__has_magic_method( '__isset' ) )
{
return $this->__run_magic_method( '__isset', array($key) );
}
else
{
return isset( $this->props[$key] );
}
}
function __unset( $key )
{
if( $this->__has_magic_method( '__unset' ) )
{
return $this->__run_magic_method( '__unset', array($key) );
}
else
{
unset( $this->props[$key] );
}
}
function __call( $key, $args )
{
if( isset( $this->props[$key] ) && is_callable( $this->props[$key] ) )
{
return call_user_func_array( $this->props[$key], $args );
}
else
{
throw new Exception( 'The key "'.addslashes($key).'" is not a callable' );
}
}
private function __keys()
{
return array_keys( $this->props );
}
static function keys( Object $obj=null )
{
if( $obj === null )
{
return array();
}
else
{
return $obj->__keys();
}
}
}
Example of usage:
$obj = new Object(array(
'__construct'=>function(){echo 'constructor executed', PHP_EOL;},
'__isset'=>function($t,$k){
echo 'checking key: ', $k, PHP_EOL;
return isset($t->{$k});
},
'test'=>5
));
if( isset($obj->test) )
{
echo $obj->test;
}
/*
Should output:
constructor executed
checking key: test
5
*/
What can I improve in this code, in terms of readability? What crimes am I committing with this code?
_
as a prefix instead. \$\endgroup\$trigger_error
instead and added support for the magic method__toString
. \$\endgroup\$