Estoy trabajando en un framework que intento escribir lo más fuerte posible. (Estoy trabajando con PHP y tomando algunas de las ideas que me gustan de C# y tratando de utilizarlas dentro de este marco.) Estoy creando una clase Collection que es una colección de entidades/objetos de dominio. Es un poco modelado después del objeto List<T>
en .Net.PHP 'instanceof' falla con constante de clase
Me encontré con un obstáculo que me impide escribir esta clase. Si tengo UserCollection, solo debería permitir objetos User en él. Si tengo una PostCollection, solo debería permitir objetos Post.
Todas las colecciones en este marco deben tener ciertas funciones básicas, como agregar, eliminar, iterar. He creado una interfaz, pero descubrió que no podía hacer lo siguiente:
interface ICollection { public function add($obj) }
class PostCollection implements ICollection { public function add(Post $obj) {} }
Esto rompió es el cumplimiento de la interfaz. Pero no puedo tener la interfaz fuertemente tipada porque todas las colecciones son del mismo tipo. Así que he intentado lo siguiente:
interface ICollection { public function add($obj) }
abstract class Collection implements ICollection { const type = 'null'; }
class PostCollection extends Collection {
const type = 'Post';
public function add($obj) {
if(!($obj instanceof self::type)) {
throw new UhOhException();
}
}
}
Cuando intento ejecutar este código, me sale syntax error, unexpected T_STRING, expecting T_VARIABLE or '$'
en la cuenta de instanceof
. Investiga un poco sobre el tema y parece que la raíz de la causa es que $obj instanceof self
es válido para probar contra la clase. Parece que PHP no procesa toda la declaración constante self::type
en la expresión. La adición de paréntesis alrededor de la variable self::type
arrojó un error con respecto a un inesperado '('.
Una solución obvia es no hacer la variable type
una constante. La expresión $obj instanceof $this->type
funciona bien (si $type
se declara como una variable, por supuesto)
Espero que haya una forma de evitar eso, ya que me gustaría definir el valor como una constante para evitar cualquier cambio posible en la variable más adelante. Cualquier idea sobre cómo puedo lograr esto, o ¿He llevado PHP a su límite en este sentido? ¿Hay alguna forma de "escapar" o encapsular self::this
para que PHP no muera al procesarlo?
ACTUALIZACIÓN Basado en los comentarios a continuación, pensé en algo para probar - ¡funciona el siguiente código! ¿Puede alguien pensar en 1) una razón para no hacer esto, 2) una razón por la cual esto no funcionará en última instancia, o 3) una mejor manera de lograrlo?
interface ICollection { public function add($obj) }
abstract class Collection { const type = null; protected $type = self::type; }
class PostCollection extends Collection {
const type = 'Post';
public function add($obj) {
if(!($obj instanceof $this->type)) {
throw new UhOhException();
}
}
}
ACTUALIZACIÓN # 2: Después de poner el código anterior en la producción, resulta que no funciona. No tengo idea de cómo funcionó cuando lo probé, pero no funciona en absoluto. Estoy atrapado con el uso de una variable protected
, creo.
creo que respondí 1 o 2 - a pesar de que t La variable está 'protegida', aún se puede cambiar en el código. No hay seguridad real al hacerlo de esta manera que la variable '$ type' no se cambiará accidentalmente. Lo que esperaba es un seguro contra eso. –
Si entiendo correctamente, le está dando a la instancia de operación una cadena ($ this-> type) cuando debería ser solo un nombre de clase (vea http://php.net/manual/en/language.operators.type.php) . Creo que deberías usar 'is_a' ya que espera una cadena que es lo que es $ this-> type. – gacrux
No es una afirmación verdadera: consulte el Ejemplo # 5 en la página a la que se ha vinculado. –