2009-07-29 18 views
27

Aquí es lo que quiero hacer:Genera dinámicamente clases en tiempo de ejecución en 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 
} 

Obviamente, esto no es lo que estoy haciendo realmente, pero básicamente tienen nombres desconocidos para una clase y basado en el nombre, quiero generar la clase con ciertas propiedades etc.

he intentado usar eval() pero está dando me queda más privada y $ this-> referencias ...

// editar

Ok, obviamente, mi corta y dulce "esto es lo que quiero hacer" causado masiva lucha y consternación entre aquellos que pueden dar respuestas. Con la esperanza de obtener una respuesta real, seré más detallado.

Tengo un marco de validación con sugerencias de código en el sitio que mantengo. Cada función tiene dos definiciones

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

Estoy buscando agregar un validador para las claves principales en mi base de datos. No quiero crear una clase separada para TODAS las tablas (203). Así que mi plan era hacer algo como

function DoSomething_Validate(vPrimaryKey_Products $id){ } 

Cuando el __autoload generaría una subclase de vPrimaryKey y establecer el parámetro de tabla a los productos.

Happy now?

+1

Le sugiero que nos diga qué es exactamente lo que está tratando de hacer, y pregúntenos cómo hacerlo mejor. Lo que estás intentando no es el enfoque correcto. – hobodave

+2

Subí este, por lo que no tiene voto negativo. Esta es una pregunta válida, incluso si es una mala idea. – MitMaro

+0

He actualizado la pregunta. –

Respuesta

4

Esto es casi seguro que es una mala idea.

Creo que le conviene más tiempo crear un script que cree las definiciones de clase para usted, y no intente hacerlo en tiempo de ejecución.

Algo con una firma de línea de comandos como:

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

Debería al menos proporcionar una razón por la cual. –

+14

Si no sabía qué era la muerte, entonces sí, debería explicarse. El OP puede no entender los problemas de seguridad al hacer esto. – MitMaro

+1

Hobodave de punto válido. – MitMaro

2

El uso de eval() es realmente una mala idea. Abre un gran agujero de seguridad. ¡Simplemente no lo use!

+1

+1 por dar la razón por la cual esta es una mala idea. – MitMaro

+13

No puedo leer esa ironía, pero como respuesta seria: 'eval()' no es inseguro por definición, si lo fuera, no habría tal función disponible. Es su entrada lo que abre los agujeros de seguridad cuando se combina con la entrada del usuario. Por ejemplo, si realiza un 'eval ('2 + 2')' o 'eval ('function() {return 42;}')' no hay ningún problema relacionado con la seguridad, incluso si tal decisión de diseño es cuestionable. –

2

Por favor, lea las respuestas de todos los demás sobre cómo esta es realmente una muy mala idea.

Una vez que comprenda eso, aquí hay una pequeña demostración de cómo podría, pero no debería, hacer esto.


<?php 
$clname = "TestClass"; 

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

var_dump($cls); 
+2

Sí, pero cuando evalúa (...) esto falla: eval ("class $ clsname {public function DoSomething() {$ this-> bob = 4;}}"); porque no puede usar "esto" en el medio de una función que no es de clase. O si estuviera en una función de clase sería el puntero "this" incorrecto ... –

+3

Tiene un problema de escape, pero me niego a ayudarlo más porque es como si todos dijeran una mala idea. – MitMaro

+1

MitMaro ... wow, debo haber estado realmente fuera de esto ayer para no notar la necesidad de escapar de mi $. Gracias. –

13

es divertido, en realidad esta es una de las pocas cosas en que duerma eval parecer una mala idea.

siempre que pueda asegurarse de que ninguna entrada del usuario ingrese alguna vez al eval.

todavía tiene inconvenientes como cuando usa un bytecode caché ese código no se almacenará en caché etc etc. pero los problemas de seguridad de eval están más o menos relacionados con tener la entrada del usuario en la evaluación, o terminar en el ámbito equivocado.

si sabes lo que estás haciendo, eval te ayudará con esto.

Dicho esto, en mi opinión es mucho mejor cuando no se basan en el tipo-dando a entender para su validación, pero tiene una función

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(); 

Esto podría ayudar a crear una clase en tiempo de ejecución También crea una ejecución methor y un método catchall para métodos desconocidos Pero es mejor crear objetos en tiempo de ejecución, no clases.

10

Sé que esta es una pregunta antigua y hay respuestas que FUNCIONARÁN, pero quería ofrecer algunos fragmentos que responderían a la pregunta original y creo que ofrecen una solución más expandida si alguien termina aquí como yo cuando buscando una respuesta a este problema.

Crear único dinámico Clase

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

Mientras escapar correctamente el texto, también se puede añadir una función en ese país.

Pero, ¿qué tal si quieres crear dinámicamente clases basadas en algo que pueda ser dinámico como crear una clase para cada tabla en tu base de datos como la pregunta original mencionada?

crear clases dinámicas múltiples

<?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); 
    } 
} 

?> 

esto va a generar dinámicamente una clase para cada tabla en una base de datos. Para cada clase, una propiedad que se nombra después de cada columna TAMBIÉN se creará.

Ahora se ha señalado que no debe hacer esto. Mientras controle lo que sucede en la evaluación, el riesgo de seguridad no es un problema. PERO, probablemente haya una solución que tenga más sentido si se piensa con suficiente profundidad al respecto. Pensé que tenía el caso de uso perfecto para crear dinámicamente nuevas clases. El examen cuidadoso del problema demostró lo contrario.

Una posible solución: utilice stdClass para crear objetos que solo sean contenedores de datos y no necesiten ningún método.

Además, como se mencionó, puede usar una secuencia de comandos para generar muchas clases manualmente. En el caso de las clases que reflejan las tablas de su base de datos, podría usar la misma lógica que tengo arriba y en lugar de hacer una evaluación, escriba esa información en un archivo.

+0

El último párrafo de su respuesta es bastante bueno: el código es el mismo para eval que para clase en archivo, así que mejor escriba esas clases en el archivo y ** tengalas en el repositorio de VCS ** – PeterM

4

Creo que usar eval() no es una solución confiable, especialmente si su script o software se distribuirá a diferentes clientes. Los proveedores de alojamiento compartido siempre desactivan la función eval().

Estoy pensando en un mejor abordaje de esta manera:

<?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(); 

Después de terminar de ejecutar el código, puede eliminar el archivo si lo desea, lo probé y funciona perfectamente.

+0

+1 para la respuesta inteligente pero. . . los riesgos de seguridad planteados por eval son ahora mayores ya que ahora has expuesto el sistema de archivos para atacar. Pero como se publicó anteriormente, si se desinfecta la información, el riesgo se minimiza. Por cierto, me encanta probar cosas como esta con '$ code =" "' – eggmatters

Cuestiones relacionadas