开发者

PHP dynamic class loading

开发者 https://www.devze.com 2023-01-15 09:31 出处:网络
Lets say that I have an array that I want to convert to a value object. My value object class is as follows:

Lets say that I have an array that I want to convert to a value object.

My value object class is as follows:

/* file UserVO.php*/
 class UserVO
 {
    public $id;
    public $email;

     public function __construct($data)
     {
         $this->id = (int)$data['id'];
         $this->email = $data['email'];
     } 
 }

And I create my array of value objects as follows:

/* file UserService.php*/
$array = array(
array(...),
array(...));
$count = count($array);
for ($i = 0; $i < $count; $i++)
{
   $result[] = new UserVO($array[$i]);
}
return $result;

O开发者_如何学编程K, so this all works fine. However, I'd like to specificy the VO that is to be created dynamically, so that I can have a single dynamic function to create my VO's.

Something like:

$ret = create_vo($array, 'UserVO');

function create_vo($data, $vo)
{
  $count = count($data);
  for ($i = 0; $i < $count; $i++)
  {
     $result[] = new $vo($data[$i]); //this obviously wont work...Class name must be a valid object or a string
  }
  return $result;
}

I realise that I could do this with a switch statement (iterating through all my VO's)...but there is no doubt a much much more elegant solution. It would also be supercool if I could lazy load the VO's as needed, instead of having multiple 'includes'

Any help much appreciated.


$result[] = new $vo($data[$i]); //this obviously wont work...Class name must be a valid object or a string

Have you tried it? It works just as expected (in php 5.1, I don't know how was it with OOP in php 4, but if you are using __construct for constructor this should work).

To avoid multiple includes define magic function __autoload before using any class

function __autoload($className)
{
    require_once 'myclasses/'.$className.'.php';
}

So first call new UserVo will trigger this function to include file myclasses/UserVo.php.


It appears that include_once()'s and require_once()'s performance is pretty bad.

My suggestion:

Kill all "require_once" and "include_once" and create an autoloader. Register this implementation


This works

<?

class UserVO
{
    public $id;
    public $email;

    public function loadData($data)
    {
        $this->id = (int)$data['id'];
        $this->email = $data['email'];
    }
}

function create_vo($data, $vo)
{
    $count = count($data);
    for ($i = 0; $i < $count; $i++)
    {
        $tmpObject = new $vo;
        $tmpObject->loadData($data[$i]);
        $result[] = $tmpObject;
        unset($tmpObject);
    }
    return $result;
}


$data = array();
$data[] = array('id'=>1,'email'=>'data@example.com');
$data[] = array('id'=>2,'email'=>'data@example.com');
$data[] = array('id'=>3,'email'=>'data@example.com');
$data[] = array('id'=>4,'email'=>'data@example.com');
$data[] = array('id'=>5,'email'=>'data@example.com');
$data[] = array('id'=>6,'email'=>'data@example.com');

$result = create_vo($data,'UserVO');

var_dump($result);

?>


First, conversion of data to an array object for UserVO should be done with ArrayObject

so

class UserVO extends ArrayObject
{
}

You are trying to use the factory method pattern and your code seems to be right, though you seem to have an forgotten to define $result as an array ($result = array()).

You can also use the ReflectionClass to pass constructor arguments as well as such:

$rc = new ReflectionClass($vo);
$rc->newInstanceArgs($data[$i]);

To "autoload" your UserVO object, you should use the spl_autoload_register function with a php include path.

0

精彩评论

暂无评论...
验证码 换一张
取 消