понедельник, 17 июня 2013 г.

Как динамически инициализировать класс РНР с динамическики параметрами.

Как динамически инициализировать класс РНР с динамическики параметрами. Вот решение.
function create_instance($class, $params) {
  $reflection_class = new ReflectionClass($class);
  return $reflection_class->newInstanceArgs($params);
}
Размышление можно просмотреть в полной статье.


Рассмотрим ситуацию когда нам нужно создать класс с параметрами. Условия храняться в Yaml файле.

class: MyClass
params: [ "value 1", { key1: "value key 1", key2: "value key 2" ]
Так это будет выглядеть наш класс. Ну где же динамика?
class myClass {
  public $arg1;
  public $arg2;
 
  public function __construct($arg1, $arg2) {
    $this->arg1 = $arg1;
    $this->arg2 = $arg2;
  }
}

$class = 'myClass';
$params = = array(
  'value 1',
  array('key1' => 'value key 1', 'key2' => 'value key 2')
);

$instance = new $class($params[0], $params[1]);

Основная проблема кроется в неопределенном количестве параматров. Попробуем найти решение

Решение 1 : плохое.

function create_instance($class, $params) {
  $inline = array();
  foreach($params as $index => $param) {
    $params[$index] = var_export($param, true);
  }

  $code = 'return new '.$class.'('.implode(', ', $params).');';
  $function = create_function('', $code);
  return $function();
}

$instance = create_instance($class, $params);

Этот метод использует create_function для инициализации класса с необходимыми параметрами. Это решение сработает с указанием класса, а вот с параметрами работать не будет. Получите ошибку: 'Call to undefined method myClass::__set_state() in index.php : runtime-created '

Эта ошибка из-за того, что var_export пытаеться вызвать не существующий метод __set_state. Этот метод очевидно плохое решение.

Решение 2 : Некрасивое.
Мы можем ограничить максимально количество аргументов - 5. Код выглядит так:
function create_instance($class, $params) {
  case(count($params)) {
    case 0: return new $class;
    case 1: return new $class($param[0]);
    case 2: return new $class($param[0], $param[1]);
    case 3: return new $class($param[0], $param[1], $param[2]);
    // and so on ...
  }
}

$instance = create_instance($class, $params);
Это решение работает, но код выглядить ужасно.

Решение 3 : Хорошее.
call_user_function_array() - наш помошник во всех случаях.
function create_instance($class, $params) {
  return call_user_func_array(
    array(new ReflectionClass($class), 'newInstance'),
    $params
  );
}

Посмотрев глубже в возможности Reflection PHP найденно идеальное решение на данный момент.
function create_instance($class, $params) {
  $reflection_class = new ReflectionClass($class);
  return $reflection_class->newInstanceArgs($params);
}

1 комментарий: