strval objeto numerico float entero convertir array php oop type-conversion downcasting

php - numerico - Emitir el objeto actual($ this) a una clase descendiente



convertir un array string a int php (4)

Casting para cambiar el tipo de objeto no es posible en PHP (sin usar una desagradable extensión). Una vez que crea una instancia de un objeto, ya no puede cambiar la clase (u otros detalles de implementación) ...

Puedes simularlo con un método como ese:

public function castAs($newClass) { $obj = new $newClass; foreach (get_object_vars($this) as $key => $name) { $obj->$key = $name; } return $obj; }

Uso:

$obj = new MyClass(); $obj->foo = ''bar''; $newObj = $obj->castAs(''myChildClass''); echo $newObj->foo; // bar

Pero ten en cuenta que en realidad no cambia la clase original. Simplemente crea uno nuevo. Y tenga en cuenta que esto requiere que las propiedades sean públicas o que tengan métodos mágicos getter y setter ...

Y si quisiera algunos controles más (lo sugeriría), agregaría esta línea como la primera línea de castAs para evitar problemas:

if (!$newClass instanceof self) { throw new InvalidArgumentException( ''Can/'t change class hierarchy, you must cast to a child class'' ); }

De acuerdo, ya que Gordon publicó una solución de magia muy negra, haré lo mismo (usando la extensión RunKit PECL (advertencia: aquí hay dragones ):

class myClass {} class myChildClass extends MyClass {} function getInstance($classname) { //create random classname $tmpclass = ''inheritableClass''.rand(0,9); while (class_exists($tmpclass)) $tmpclass .= rand(0,9); $code = ''class ''.$tmpclass.'' extends ''.$classname.'' {}''; eval($code); return new $tmpclass(); } function castAs($obj, $class) { $classname = get_class($obj); if (stripos($classname, ''inheritableClass'') !== 0) throw new InvalidArgumentException( ''Class is not castable'' ); runkit_class_emancipate($classname); runkit_class_adopt($classname, $class); }

Entonces, en lugar de hacer un new Foo , harías algo como esto:

$obj = getInstance(''MyClass''); echo $obj instanceof MyChildClass; //false castAs($obj, ''myChildClass''); echo $obj instanceof MyChildClass; //true

Y desde dentro de la clase (siempre que se haya creado con getInstance ):

echo $this instanceof MyChildClass; //false castAs($this, ''myChildClass''); echo $this instanceof MyChildClass; //true

Descargo de responsabilidad: No hagas esto. Realmente, no. Es posible, pero es una idea tan horrible ...

Tengo una clase donde puede ser necesario cambiar el objeto a una clase descendiente más adelante en la línea. es posible? Sé que una opción es devolver una copia pero usando la clase secundaria, pero sería bueno modificar el objeto actual ... así que:

class myClass { protected $var; function myMethod() { // function which changes the class of this object recast(myChildClass); } } class myChildClass extends myClass { } $obj = new myClass(); $obj->myMethod(); get_class_name($obj); // => myChildClass


Esto no es posible porque, aunque una instancia de una clase hija también es una instancia de una clase padre, lo contrario no es verdadero.

Lo que podría hacer es crear una nueva instancia de la clase secundaria y copiar los valores del antiguo objeto en ella. A continuación, puede devolver el nuevo objeto que será de tipo myChildClass .


Puedes, como se describe en otras respuestas, hacerlo con desagradables extensiones PECL de magia negra .

Sin embargo, en serio no lo quieres. Cualquier problema que desee resolver en OOP existe una forma compatible con OOP para hacerlo.

Las modificaciones de la jerarquía del tipo de tiempo de ejecución no son compatibles con OOP (de hecho, esto se evita conscientemente). Hay patrones de diseño que deberían ajustarse a lo que desea.

Díganos por qué lo quiere, estoy seguro de que debe haber mejores formas de hacerlo;)


Redefiniendo las clases

Puedes hacer esto con la extensión Runkit PECL también conocida como "Toolkit from Hell":

  • runkit_class_adopt - Convierta una clase base en una clase heredada, agregue métodos ancestrales cuando sea apropiado
  • runkit_class_emancipate - Convierta una clase heredada a una clase base, elimina cualquier método cuyo alcance sea ancestral

Redefiniendo instancias

Las funciones de runkit no funcionan en instancias de objetos. Si desea hacer eso en instancias de objetos, en teoría podría hacerlo al interferir con las cadenas de objetos serializados.
Sin embargo, este es el reino de la magia negra .

El código siguiente le permite cambiar una instancia a cualquier otra clase:

function castToObject($instance, $className) { if (!is_object($instance)) { throw new InvalidArgumentException( ''Argument 1 must be an Object'' ); } if (!class_exists($className)) { throw new InvalidArgumentException( ''Argument 2 must be an existing Class'' ); } return unserialize( sprintf( ''O:%d:"%s"%s'', strlen($className), $className, strstr(strstr(serialize($instance), ''"''), '':'') ) ); }

Ejemplo:

class Foo { private $prop1; public function __construct($arg) { $this->prop1 = $arg; } public function getProp1() { return $this->prop1; } } class Bar extends Foo { protected $prop2; public function getProp2() { return $this->prop2; } } $foo = new Foo(''test''); $bar = castToObject($foo, ''Bar''); var_dump($bar);

Resultado:

object(Bar)#3 (2) { ["prop2":protected]=> NULL ["prop1":"Foo":private]=> string(4) "test" }

Como puede ver, el objeto resultante es un objeto Bar ahora con todas las propiedades conservando su visibilidad, pero prop2 es NULL . El controlador no permite esto, por lo que, técnicamente, mientras tenga un Bar hijo de Foo , no está en un estado válido. Podría agregar un método mágico __wakeup para manejar esto de alguna manera, pero en serio, no quiere eso y muestra por qué el casting es un asunto desagradable.

DESCARGO DE RESPONSABILIDAD: Absolutamente no animo a nadie a usar cualquiera de estas soluciones en producción.