2009-10-20 10 views
7

por lo que quiero ser capaz de añadir/eliminar los métodos de clase en tiempo de ejecución. Antes de que me digas que es una práctica horrible en un principio, podría ser, pero realmente no me importa. La razón por la que deseo poder hacer esto es porque quiero que la aplicación sea muy modular, por lo que algunos complementos podrían ampliar alguna clase base y agregar métodos sin matar a la aplicación principal.PHP modificación de clase en tiempo de ejecución

Por ejemplo, decir que tengo la clase siguiente:

class User { 
    protected $Id; 
    protected $Name; 
    protected $Password; 
    protected $PostsPerPage; 
} 

Y digo, algunos plugin añade la posibilidad de que los usuarios cambiar sus ajustes de visibilidad, la adición de un $ propiedad visible en la clase. La clase se convertiría en:

class User { 
    protected $Id; 
    protected $Name; 
    protected $Password; 
    protected $PostsPerPage; 
    protected $Visible; 
} 

Esto podría lograrse a través de __get y __set, pero la aplicación más común es para obtener y establecer las propiedades de ejecución generado, y que sería una molestia para pseudo código captadores y definidores para cada propiedad agregada, así como el uso de __set es un no-no en mi opinión.

La otra idea que tuve fue almacenar la configuración del usuario por separado, en otra matriz como $ UserVisiblitySettings [userid], pero eso no hace que las cosas sean como OO como me gustaría.

siguiente idea era hacer una clase de ayuda, algo como esto:

class UserHelper { 
    public function SetVisiblity($user_object,value); 
} 

Entonces, podría usar __get y __set para implementar "amigos" métodos/clases, pero que suena demasiado hacker. Si tuviera que ir por ese camino también podría sobrecargar __call, __get y __set. Además, no estoy tan seguro de que esta sea una buena práctica de OOP, y se vería feo también.

La última idea que tenía era tener alguna función para crear clases dinámicamente en tiempo de ejecución mediante el uso de eval() (esta es la única válida uso de eval pude llegar a también). Básicamente, obtenga la definición de la clase de un archivo, haga una búsqueda simple de corchetes para encontrar los corchetes de apertura y cierre de la clase y envíelos a eval.

Usando runkit está fuera de cuestión, ya que es obsoleto y prefiero no forzar al usuario a instalar alguna extensión.

Cuando miro a mis ideas, la más sencilla y menos intensivo de la CPU parece ser sobrecargar _call y añadir una forma de que los métodos que se registran en la clase.

Por favor, cualquier pensamiento que no son "no hacen esto" son apreciados.

+0

Esencialmente usted está buscando un homólogo de extender incluir mecanismo (http://ruby-doc.org/core/classes/Object.html#M000335) o (en cierta medida) los métodos de extensión de rubí/C# 's (http://msdn.microsoft.com/en-us/library/bb383977.aspx)? – VolkerK

+0

Exactamente como los métodos de extensión de C# – stelonix

Respuesta

6

RunKit extensión puede hacerlo (runkit_method_add(), etc.)

Sin embargo, es una extensión experimental y que ya está apuntando en su pie ...

tiene otras opciones:

  • Emular nuevos campos y métodos con __get() y __call()
  • uso de subclases y el patrón de fábrica (class Plugin extends BaseImplementation fábrica y tienen una instancia Plugin en lugar de BaseImplementation). Zend Plugin Loader hace algo como esto.
    Es la solución con menos gastos generales, pero también está limitada a un complemento que extiende una clase.
  • Añadir ganchos y usar delegación (Patrón de estrategia) ($this->plugin->onFoo()). There's library for this.
+0

Creo que el método Factory tiene algunas limitaciones que no puedo recordar en este momento. Lo intentaré de cualquier manera. – stelonix

+1

La solución de fábrica está limitada a un complemento que extiende una clase. Use algo como espátula si necesita una cantidad arbitraria de complementos. – Kornel

+0

Usando __call junto con el patrón de localizador he encontrado infinitamente útil para situaciones como esta. Aquí hay un ejemplo: https://github.com/treshugart/EuropaPHP/tree/master/lib/Europa/View#using-helpers. – Tres

3

PHP no permite esto. Puede ser un lenguaje dinámico en otros aspectos, pero el sistema de clases es deliberadamente restrictivo. Puede instalar la extensión runkit, que cambia el idioma para permitir burlas acerca de las clases en tiempo de ejecución (Pero entonces usted no está usando PHP plano ya no), o puede utilizar la magic-methods para simularlo.

1

Puede anular la clase, pero no sé si puede volver a cargarla en la misma solicitud. se puede lograr algún cambio de comportamiento con el patrón de diseño de mediador (operador de eventos Symfony) pero necesita conocer los puntos de extensión por adelantado y disparar eventos/mensajes para atraparlos en el futuro.

si puede esperar la próxima solicitud y borrar la caché si la tiene. Hice una herramienta que podría ayudarte. SourceEditor

Aquí hay más respuestas a una pregunta similar también, donde pongo ejemplos de código. How to generate or modify a PHP class at runtime?

Cuestiones relacionadas