2009-07-29 8 views
27

Вот что я хочу сделать:Динамически генерировать классы во время выполнения в php?

$clsName = substr(md5(rand()),0,10); //generate a random name 
$cls = new $clsName(); //create a new instance 

function __autoload($class_name) 
{ 
    //define that instance dynamically 
} 

Очевидно, что это не то, что я на самом деле делает, но в основном у меня есть неизвестные имена для класса и на основе имени, я хочу, чтобы создать класс с некоторые свойства и т.д.

Я попытался с помощью Eval(), но это дает мне надевается приватным и $ this-> ссылки ...

// редактировать

Ok, очевидно, мой короткий и сладкий «вот что я хочу сделать» вызвал ма сильная борьба и страх среди тех, кто может дать ответы. В надежде получить реальный ответ я буду более подробно.

У меня есть структура проверки, использующая подсказки кода на сайте, который я поддерживаю. Каждая функция имеет два определения

function DoSomething($param, $param2){ 
    //code 
} 
function DoSomething_Validate(vInteger $param, vFloat $param2){ 
    //return what to do if validation fails 
} 

Я ищу, чтобы добавить валидатор первичных ключей в мою базу данных. Я не хочу создавать отдельный класс для КАЖДОЙ таблицы (203). Так что мой план был сделать что-то вроде

function DoSomething_Validate(vPrimaryKey_Products $id){ } 

Если __autoload будет генерировать подкласс vPrimaryKey и установите параметр таблицы на продукты.

С большим удовольствием?

+1

Предлагаю вам рассказать нам, что именно вы пытаетесь сделать, и спросить нас, как это сделать лучше. То, что вы пытаетесь, является неправильным подходом. – hobodave

+2

Я поддержал это, поэтому у него не было отрицательного голоса. Это правильный вопрос, даже если это плохая идея. – MitMaro

+0

Я обновил вопрос. –

ответ

4

Это почти наверняка плохая идея.

Я думаю, ваше время было бы лучше потрачено на создание сценария, который создавал бы для вас определения классов, а не во время выполнения.

Что-то с командной строки подписи как:

./generate_classes_from_db <host> <database> [tables] [output dir] 
+9

Вы должны хотя бы указать причину. –

+14

Если вы не знали, что такое смерть, то да, это должно быть объяснено. ОП может не понимать проблемы безопасности при этом. – MitMaro

+1

Действительный пункт hobodave. – MitMaro

2

Использование Eval() действительно плохая идея. Это открывает большую дыру в безопасности. Просто не используйте его!

+1

+1 за причину, почему это плохая идея. – MitMaro

+13

Я, возможно, не читаю эту иронию, но как серьезный ответ - 'eval()' не является необеспеченным по определению, если бы это было так, такой функции не было бы. Это его вклад, который открывает дыры в безопасности, когда он сочетается с пользовательским вводом. Например, если вы выполняете 'eval ('2 + 2')' или 'eval ('function() {return 42;}')' нет проблемы с безопасностью, даже если такое конструктивное решение вызывает сомнения. –

2

Пожалуйста, прочитайте все остальные ответы о том, как это действительно очень плохая идея.

Как только вы это понимаете, вот небольшая демонстрация о том, как вы могли, но не должны этого делать.


<?php 
$clname = "TestClass"; 

eval("class $clname{}; \$cls = new $clname();"); 

var_dump($cls); 
+2

Да, но когда вы делаете eval (...), это не удается: eval ("class $ clsname {public function DoSomething() {$ this-> bob = 4;}}"); , потому что вы не можете использовать «это» в середине функции, отличной от класса. Или, если бы я был в функции класса, это был бы неправильный «этот» указатель ... –

+3

У вас есть проблема с экранированием, но я отказываюсь больше помогать тогда, потому что это похоже на то, что все говорят плохую идею. – MitMaro

+1

MitMaro ... ничего себе, я, должно быть, вчера был действительно из этого, чтобы не заметить, что мне нужно сбежать от моего доллара. Благодарю. –

13

его смешно, на самом деле это одна из немногих вещей, где Eval не кажется такой плохой идеей.

до тех пор, пока вы не можете гарантировать, что пользовательский ввод никогда не войдет в eval.

У вас все еще есть недостатки, например, когда вы используете кеш-байт-код, который не будет кэшироваться и т. Д., Но проблемы безопасности eval в значительной степени связаны с наличием ввода пользователя в eval или заканчиванием в неправильной области.

Если вы знаете, что делаете, eval поможет вам в этом.

Тем не менее, на мой взгляд, вы гораздо лучше, если вы не полагаться на тип-намекая для проверки, но у вас есть одна функция

DoSomething_Validate($id) 
{ 
    // get_class($id) and other validation foo here 
} 
3
function __autoload($class) { 
    $code = "class $class {` 
     public function run() { 
      echo '$class<br>'; 
     } 
     ".' 
     public function __call($name,$args) { 
      $args=implode(",",$args); 
      echo "$name ($args)<br>"; 
     } 
    }'; 

    eval($code); 
} 

$app=new Klasse(); 
$app->run(); 
$app->HelloWorld(); 

Это может помочь создать класс в во время выполнения. Он также создает прогон меток и метод catchaw для неизвестных методов. Но лучше создавать объекты во время выполнения, а не в классах.

10

Я знаю, что это старый вопрос, и есть ответы, которые будут работать, но я хотел бы предложить несколько фрагментов, которые отвечали бы на исходный вопрос, и я думаю, что предлагаю более расширенное решение, если кто-то окажется здесь, как я сделал, когда поиск ответа на эту проблему.

Создание единого динамического класса

<?php 
// Without properties 
$myclassname = "anewclassname"; 
eval("class {$myclassname} { }"; 
// With a property 
$myclassname = "anewclassname"; 
$myproperty = "newproperty"; 
eval("class {$myclassname} { protected \${$myproperty}; }"; 
?> 

Пока вы правильно бежать текст, можно также добавить функцию там.

А как насчет того, хотите ли вы динамически создавать классы на основе того, что может быть динамическим, например, создание класса для каждой таблицы в вашей базе данных в качестве исходного вопроса?

Создание нескольких динамических классов

<?php 

// Assumes $dbh is a pdo connection handle to your MySQL database 
$stmt=$dbh->prepare("show tables"); 
$stmt->execute(); 
$result = $stmt->fetchAll(PDO::FETCH_ASSOC); 
$handle = null; 
$classcode = ''; 
foreach ($result as $key => $value) { 
    foreach ($value as $key => $value) { 
     $classcode = "class {$value} { "; 
     $stmt2=$dbh->prepare("DESC $value"); 
     $stmt2->execute(); 
     $result2 = $stmt2->fetchAll(PDO::FETCH_ASSOC); 
     foreach ($result2 as $key => $value) { 
      $classcode .= "public \${$value['Field']}; "; 
     } 
     $classcode .= "}"; 
     eval($classcode); 
    } 
} 

?> 

Это будет динамически генерировать класс для каждой таблицы в базе данных. Для каждого класса также будет создано свойство, названное в честь каждого столбца.

Теперь было указано, что вы не должны этого делать. Пока вы контролируете, что происходит в eval, риск безопасности не является проблемой. НО - есть, скорее всего, решение, имеющее больше смысла, если вы достаточно глубоко задумаетесь об этом. Я думал, что у меня есть идеальный вариант использования для динамического создания новых классов. Тщательное рассмотрение проблемы оказалось иным.

Одно из возможных решений - использовать stdClass для создания объектов, которые являются контейнерами данных и не нуждаются в каких-либо методах.

Кроме того, как уже упоминалось, вы можете использовать скрипт для ручного создания множества классов. В случае классов, отражающих ваши таблицы базы данных, вы можете использовать ту же логику, что и я, и вместо того, чтобы делать eval, пишите эту информацию в файл.

+0

Последний параграф вашего ответа довольно хорош - код такой же для eval, как и для класса в файле, поэтому лучше пишите эти классы в файл и ** имейте их в репозитории VCS ** – PeterM

4

Я думаю, что с помощью eval() это не надежное решение, особенно если ваш скрипт или программное обеспечение будет распространяться среди разных клиентов. Общие хостинг-провайдеры всегда отключают функцию eval().

Я думаю лучше ПОДХОД так:

<?php 

function __autoload($class) { 
     require 'classes/'.$class.'.php'; 

} 

$class = 'App'; 
$code = "<?php class $class { 
    public function run() { 
     echo '$class<br>'; 
    } 
    ".' 
    public function __call($name,$args) { 
     $args=implode(",",$args); 
     echo "$name ($args)<br>"; 
    } 
}'; 

file_put_contents('classes/App.php' ,$code); 

$a = new $class(); 
$a->run(); 

После завершения выполнения кода, вы можете удалить файл, если вы хотите, я проверил его и он работает отлично.

+0

+1 для умного ответа. , , риски безопасности, создаваемые eval, теперь больше, поскольку теперь вы открыли файловую систему для атаки. Но, как отмечают выше, если вводят санированные данные, риск минимизируется. BTW, мне нравится тестировать такие вещи, как «$ code =» "' – eggmatters

Смежные вопросы