За последние 24 часа нас посетил 17551 программист и 1722 робота. Сейчас ищут 909 программистов ...

Подскажите как избавится от eval()?

Тема в разделе "Прочие вопросы по PHP", создана пользователем enshtein, 20 сен 2007.

  1. enshtein

    enshtein Активный пользователь

    С нами с:
    27 авг 2006
    Сообщения:
    291
    Симпатии:
    0
    Собственно проблема перекочевала из темы http://php.ru/forum/viewtopic.php?t=7759
    Там обсуждалась такая весчь:
    PHP:
    1. class MyClass {
    2.  
    3.     // конструктор
    4.     function MyClass() {
    5.         echo get_class($this);
    6.     }
    7. }
    8.  
    9. function &NewObject($class) {
    10.     return new $class();
    11. }
    12.  
    13. $obj = NewObject('MyClass');
    Т.е., функция NewObject() создает экземпляр класса MyClass, при создании естественно вызывается метод-конструктор если он описан в классе!
    Так вот проблема в следующем, частенько при создании экземпляра объекта в метод-конструктор необходимо передать некое кол-во параметров, а выше описанная функция NewObject этого делать не умеет!
    Переписав вышеприведенный код таким образом:
    PHP:
    1. class MyClass {
    2.  
    3.     // конструктор
    4.     function MyClass($arg1, $arg2) {
    5.         var_dump($arg1);
    6.         var_dump($arg2);
    7.     }
    8. }
    9.  
    10. function &NewObject($class, $args) {
    11.     $args_str = implode(',', $args);
    12.     eval("return new $class($args_str);");
    13. }
    14.  
    15. $obj = NewObject('MyClass', array('text', 1));
    мы получаем возможность вместе с названием класса передавать также и массив параметров в функцию NewObject - которая в свою очередь воткнет эти параметры как значения аргументов конструктора инициализируемого класса!
    Однако такое решение, да и еще с применением eval() меня не совсем устраивает!
    Подскажите пожалуйста алтернативное решение проблемы но только без использования eval()
     
  2. Ивашка

    Ивашка Активный пользователь

    С нами с:
    29 авг 2007
    Сообщения:
    96
    Симпатии:
    0
    Адрес:
    Щёкино/Тула
  3. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    ну и чего ты так эвала боишься? evil напоминает? :)

    а вообще, я сторонник отделения создания объекта от его инициализации параметрами:

    $var= new Class();
    $var->InitType1( 1,2,3 );

    $var2= new Class();
    $var2->InitType2( array( 1,2,3 ) );

    и _опциональная_ поддержка дефолтного инициализатора:
    $var3= new Class( 1,2,3 );
     
  4. enshtein

    enshtein Активный пользователь

    С нами с:
    27 авг 2006
    Сообщения:
    291
    Симпатии:
    0
    и что мне это дает??? :)
    можно конечно сделать так:
    PHP:
    1. class MyClass {
    2.  
    3.     // конструктор
    4.      function MyClass($arg1, $arg2) {
    5.          var_dump($arg1);
    6.          var_dump($arg2);
    7.      }
    8. }
    9.  
    10.  
    11. function &NewObject($class, $args) {
    12.     return call_user_func_array(array($class, $class), $args);
    13. }
    14.  
    15. $args = array('text', 1024);
    16. $obj = NewObject('MyClass', $args);
    но NewObject() ничего не вернет! и var_dump($obj) будет равен NULL
    Хотя самое интересное, что конструктор MyClass() сработает. И сработает непонятно как, ведь с одной стороны функции MyClass() несуществует, но с другой стороны как можно вызвать метод без создания экземпляра-объекта??
     
  5. Ивашка

    Ивашка Активный пользователь

    С нами с:
    29 авг 2007
    Сообщения:
    96
    Симпатии:
    0
    Адрес:
    Щёкино/Тула
    Сорри, немного ошибся, call_user_func_array здесь не совсем подходит.
    Конечно, можно было бы ее использовать, но для этого придется в каждом классе создавать статический метод, возвращающий экземпляр объекта... В общем, геморрой :)

    Если для вас важно именно устранение eval'а, то можно воспользоваться runtime-created функциями:
    PHP:
    1. <?php
    2.  
    3. function &NewObject($class, $args) {
    4.   $caller = create_function('', "return new $class(".implode(',',$args).");");
    5.   return $caller();
    6. }
    7.  
    8. ?>
    но учтите, что этот способ работает несколько медленнее, чем eval.
    Других решений этой задачи я уже не вижу.
     
  6. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    не, а что? фабрику классов уже не написать?
     
  7. Ивашка

    Ивашка Активный пользователь

    С нами с:
    29 авг 2007
    Сообщения:
    96
    Симпатии:
    0
    Адрес:
    Щёкино/Тула
    Фабрика классов не решит проблемы переменного количества аргументов конструктора.
     
  8. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    ну передавай массив, кто мешает?

    но я бы не передавал параметры именно в конструктор а вызывал соотв. методы уже после инициализации экземпляра.
     
  9. Ивашка

    Ивашка Активный пользователь

    С нами с:
    29 авг 2007
    Сообщения:
    96
    Симпатии:
    0
    Адрес:
    Щёкино/Тула
    Мне никто :) а у автора топика именно такая проблема и возникла.
    Я поэтому и написал, что других решений нет, только eval или create_function.
     
  10. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    +1

    я вот тоже склонен к решению проблем а не их обмусоливанию.
     
  11. ustas

    ustas Активный пользователь

    С нами с:
    17 сен 2007
    Сообщения:
    59
    Симпатии:
    0
    enshtein
    $params = func_get_args();
    хоть сто параметров передавай.

    # function &NewObject($class, $args) {
    # return call_user_func_array(array($class, $class), $args);
    # }
    учи матчасть. юзай __set, помотри zf
     
  12. vb

    vb Активный пользователь

    С нами с:
    6 июн 2006
    Сообщения:
    911
    Симпатии:
    0
    Адрес:
    Saint-Petersburg
    enshtein
    PHP:
    1. <?
    2. class MyClass {
    3. function MyClass (){
    4. //...
    5. }
    6.  
    7. function Init ($a, $b) {
    8. //...
    9. }
    10. }
    11.  
    12. $ClassName = "MyClass";
    13. $instance = new $ClassName;
    14. $instance->Init ($a, $b)
    15. ?>
     
  13. enshtein

    enshtein Активный пользователь

    С нами с:
    27 авг 2006
    Сообщения:
    291
    Симпатии:
    0
    ладно убедили, конструктор в топку, спец. метод инициализации в класс :)
     
  14. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Ребята, вы что-то тупите....

    PHP:
    1. <?php
    2. class Core {
    3.      
    4.       function Core($param){
    5.       }
    6. }
    7.  
    8. $class = 'Co'.'re';
    9. $object = new $class($some_param);
    10. // идентично ниже написанному
    11. $object = new Core($some_param);
    12.  
    KISS - Keep It Simple Stupid

    Вы как всегда превратили простейшую и давно решенную проблему в слона.
     
  15. enshtein

    enshtein Активный пользователь

    С нами с:
    27 авг 2006
    Сообщения:
    291
    Симпатии:
    0
    да мы то не тупим.... :) это просто ты не понял всей проблемы, да конечно в твоем примере с одним параметров все просто, можно переписав на мой пример получить следующее:
    PHP:
    1. class MyClass {
    2.  
    3.      // конструктор
    4.      function MyClass($arg1) {
    5.          echo $arg1;
    6.      }
    7. }
    8.  
    9. function &NewObject($class, $args) {
    10.     return new $class($args);
    11. }
    12.  
    13. $obj = NewObject('MyClass', 'параметр');
    Только вот не задумывался ли ты что аргументов (параметров) для конструктора может быть не один, а произвольное кол-во! К примеру:
    PHP:
    1. class MyClass {
    2.  
    3.      // конструктор
    4.      function MyClass($arg1, $arg2) {
    5.          var_dump($arg1);
    6.          var_dump($arg2);
    7.      }
    8. }
    9.  
    10. function &NewObject($class, $args) {
    11.     return new $class($args);
    12. }
    13.  
    14. $obj = NewObject('MyClass', 'параметр1', 'параметр2');
     
  16. vb

    vb Активный пользователь

    С нами с:
    6 июн 2006
    Сообщения:
    911
    Симпатии:
    0
    Адрес:
    Saint-Petersburg
    Psih
    +1 :)))) Память ужо не та :)
     
  17. vb

    vb Активный пользователь

    С нами с:
    6 июн 2006
    Сообщения:
    911
    Симпатии:
    0
    Адрес:
    Saint-Petersburg
    нет, мы тупим :)
    Да, это уже другая задача. При использовании метода инициализации объекта у тебя она так же возникнет. Подумай сам как лучше сделать.
     
  18. enshtein

    enshtein Активный пользователь

    С нами с:
    27 авг 2006
    Сообщения:
    291
    Симпатии:
    0
    блиннн, но
    PHP:
    1. $object = new $class($some_param);
    здесь $some_param - один параметр, а если надо передавать через функцию несколько!
     
  19. vb

    vb Активный пользователь

    С нами с:
    6 июн 2006
    Сообщения:
    911
    Симпатии:
    0
    Адрес:
    Saint-Petersburg
    $object = new $class($some_param, $some_param2, $some_param3, $some_param4);
    Так чтоли? :)
     
  20. enshtein

    enshtein Активный пользователь

    С нами с:
    27 авг 2006
    Сообщения:
    291
    Симпатии:
    0
    блиннн... ну а как же ты это передавать то в функцию будешь??? а???

    вот жишь я приводил пример:

    PHP:
    1. class MyClass {
    2.  
    3.      // конструктор
    4.      function MyClass($arg1, $arg2=0, $ar3=0) {
    5.          var_dump($arg1);
    6.          var_dump($arg2);
    7.          var_dump($arg3);
    8.      }
    9.  }
    10.  
    11.  function &NewObject($class) {
    12.      return new $class(>>>>>>ЗДЕСЬ МОЖЕТ БЫТЬ ПРОИЗВОЛЬНОЕ КОЛ-ВО ПАРАМЕТРОВ А МОЖЕТ И ВООБЩЕ НЕ БЫТЬ! ВОПРОС КАК СЮДА ПЕРЕДАТЬ ИХ ЧЕРЕЗ ФУНКЦИЮ NewObject??????<<<<<<);
    13.  }
    14.  
    15. $obj = NewObject('MyClass', 'параметр1');
    16. $obj1 = NewObject('MyClass', 'параметр1', 'параметр2');
    17. $obj2 = NewObject('MyClass', 'параметр1', 'параметр2', 'параметр3');
    18.  
    19.  
     
  21. vb

    vb Активный пользователь

    С нами с:
    6 июн 2006
    Сообщения:
    911
    Симпатии:
    0
    Адрес:
    Saint-Petersburg
    Вариант 1: Передавать массив.
    PHP:
    1. <?
    2. $className = 'CMyClass';
    3. $params = array ();
    4. $params[0] = 1;
    5. $params[1] = 2;
    6. $params['DB'] = &$ExpGlobal['DB']; //=)
    7. $Obj = NewObject ($className, $params);
    8.  
    9. function &NewObject ($className, $params)
    10. {
    11.     return new $className ($params);
    12. }
    13.  
    14. class CMyClass {
    15. var $data = array ();
    16. var $db;
    17.  
    18.     function CMyClass(&$params)
    19.     {
    20.         $this->data[0] = $params[0];
    21.         $this->data[1] = $params[1];
    22.  
    23.         $this->db = &$params['DB'];
    24.     }
    25.  
    26. }
    27. ?>
    Вариант 2:
    Использовать метод инициализации. Но тут с таким же успехом можно инициализацию заменить на $class(...)
    PHP:
    1. <?
    2. class Instance {
    3.   function Init (){
    4.   }
    5. }
    6. class CMyClass extends Instance {
    7.  
    8. function get_result (){
    9. //....
    10. }
    11. }
    12. class CMyClass2 extends Instance {
    13. var $a;
    14. var $b;
    15. function Init ($a, $b){
    16.   $this->a = $a;
    17.   $this->b = $b;
    18. }
    19. }
    20.  
    21. function &NewObject ($className){
    22.  
    23.   $arg_list = func_get_args();
    24.  
    25.   $obj = new $class;
    26.  
    27.   switch ($className) //точно так же можно сделать new $class. Плюс в том что не надо тянуть лишний метод
    28.   {
    29.      case 'CMyClass':
    30.         $obj->Init();
    31.      break;
    32.      case 'CMyClass2':
    33.         $obj->Init($arg_list[1], $arg_list[2]);
    34.      break;
    35.   }
    36.   return $obj;
    37. }
    38.  
    39. $a = NewObject('MyClass');
    40. $b = NewObject('MyClass2', 1, 2);
    41.  
    42. ?>
    43.  
    Вариант 3: ... предлагайте :)
     
  22. enshtein

    enshtein Активный пользователь

    С нами с:
    27 авг 2006
    Сообщения:
    291
    Симпатии:
    0
    да видно я всеже остановлюсь на преусловатом eval'e отчего бежал к тому и прибежал :)
    PHP:
    1. class MyClass {
    2.  
    3.      // конструктор
    4.      function MyClass($arg1, $arg2) {
    5.          var_dump($arg1);
    6.          var_dump($arg2);
    7.      }
    8.  }
    9.  
    10.  function &NewObject($class, $args) {
    11.      $args_str = implode(',', $args);
    12.      eval("return new $class($args_str);");
    13.  }
    14.  
    15.  $obj = NewObject('MyClass', array('text', 1));
     
  23. vb

    vb Активный пользователь

    С нами с:
    6 июн 2006
    Сообщения:
    911
    Симпатии:
    0
    Адрес:
    Saint-Petersburg
    Да, в данном случае это оправдонное зло :)