Crear objetos anónimos en php


141

Como sabemos, crear objetos anónimos en JavaScript es fácil, como el siguiente código:

var object = { 
    p : "value", 
    p1 : [ "john", "johnny" ]
};

alert(object.p1[1]);

Salida:

an alert is raised with value "johnny"

¿Se puede aplicar esta misma técnica en PHP? ¿Podemos crear objetos anónimos en PHP?


1
Nota: esta es una pregunta antigua, por lo que la respuesta aceptada no está actualizada. Esta característica solicitada ahora se ha agregado a PHP 7. Consulte la respuesta a continuación por @ Rizier123.
Simba

@Simba - Gracias por señalarlo. ¿Le gustaría publicar una respuesta en StackOverflow aquí en esta página para ayudar a futuros visitantes?
Sujit Agarwal

1
No necesito ya hay una respuesta con esta información (ver más abajo, por @ Rizier123).
Simba

Respuestas:


40

Han pasado algunos años, ¡pero creo que necesito mantener la información actualizada!

Desde PHP 7 ha sido posible crear clases anónimas, por lo que puede hacer cosas como esta:

<?php

    class Foo {}
    $child = new class extends Foo {};

    var_dump($child instanceof Foo); // true

?>

Puedes leer más sobre esto en el manual

Pero no sé qué tan similar se implementa a JavaScript, por lo que puede haber algunas diferencias entre las clases anónimas en JavaScript y PHP.


@risyasin Gracias, actualicé la respuesta y puse el enlace del manual en ella.
Rizier123

Marcar su respuesta como correcta para mantenerse al día con los últimos cambios en php7. Gracias @ Rizier123
Sujit Agarwal

3
Esto es interesante, pero en realidad no aborda la pregunta, ya que el OP estaba preguntando sobre una forma conveniente de inicializar un objeto con varios miembros sin crear una clase. No estoy seguro de si las clases anónimas en php pueden usarse para hacer eso, y si puede, no explicaste cómo.
amh15

228

"Anónimo" no es la terminología correcta cuando se habla de objetos. Sería mejor decir "objeto de tipo anónimo ", pero esto no se aplica a PHP.

Todos los objetos en PHP tienen una clase. La clase "predeterminada" es stdClass, y puede crear objetos de esta manera:

$obj = new stdClass;
$obj->aProperty = 'value';

También puede aprovechar la conversión de una matriz a un objeto para una sintaxis más conveniente:

$obj = (object)array('aProperty' => 'value');
print_r($obj);

Sin embargo, tenga en cuenta que lanzar una matriz a un objeto probablemente arroje resultados "interesantes" para aquellas claves de matriz que no son nombres de variables PHP válidos; por ejemplo, aquí hay una respuesta mía que muestra lo que sucede cuando las claves comienzan con dígitos.


1
¿Puedo empujar una matriz de valores múltiples también?
Sujit Agarwal

2
@CodingFreak: puede, pero : si la matriz contiene sub-matrices y desea que también sean objetos, deberá convertir cada una de ellas en un objeto explícito.
Jon

21

¡Sí, es posible! Usando esta simple clase de Objeto Anónimo de PHP . Cómo funciona:

// define by passing in constructor
$anonim_obj = new AnObj(array(
    "foo" => function() { echo "foo"; }, 
    "bar" => function($bar) { echo $bar; } 
));

$anonim_obj->foo(); // prints "foo"
$anonim_obj->bar("hello, world"); // prints "hello, world"

// define at runtime
$anonim_obj->zoo = function() { echo "zoo"; };
$anonim_obj->zoo(); // prints "zoo"

// mimic self 
$anonim_obj->prop = "abc";
$anonim_obj->propMethod = function() use($anonim_obj) {
    echo $anonim_obj->prop; 
};
$anonim_obj->propMethod(); // prints "abc"

Por supuesto, este objeto es una instancia de AnObjclase, por lo que no es realmente anónimo, pero permite definir métodos sobre la marcha, como lo hace JavaScript.


Puede usar create_function para emular una función anónima.
Mihailoff

Creo que solo quería una forma ordenada de inicializar un objeto stdClass con algunos valores. ¿Puedes hacer eso con tu enfoque?
amh15

18

Hasta hace poco, así es como creé objetos sobre la marcha.

$someObj = json_decode("{}");

Luego:

$someObj->someProperty = someValue;

Pero ahora voy con:

$someObj = (object)[];

Entonces como antes:

$someObj->someProperty = someValue;

Por supuesto, si ya conoce las propiedades y los valores, puede establecerlos dentro como se ha mencionado:

$someObj = (object)['prop1' => 'value1','prop2' => 'value2'];

NB: No sé en qué versiones de PHP funciona esto, por lo que deberá tenerlo en cuenta. Pero creo que el primer enfoque (que también es corto si no hay propiedades para establecer en la construcción) debería funcionar para todas las versiones que tienen json_encode / json_decode


1
¿Cómo es eso diferente de ir $ someObj = new \ stdClass ()?
JamesNZ

9

Convierta la matriz en un objeto (pero esto no es recursivo para los hijos secundarios):

$obj = (object)  ['myProp' => 'myVal'];

7

Si desea imitar JavaScript, puede crear una clase Objecty así obtener el mismo comportamiento. Por supuesto, esto ya no es anónimo, pero funcionará.

<?php 
class Object { 
    function __construct( ) { 
        $n = func_num_args( ) ; 
        for ( $i = 0 ; $i < $n ; $i += 2 ) { 
            $this->{func_get_arg($i)} = func_get_arg($i + 1) ; 
        } 
    } 
} 

$o = new Object( 
    'aProperty', 'value', 
    'anotherProperty', array('element 1', 'element 2')) ; 
echo $o->anotherProperty[1];
?>

Eso dará salida al elemento 2 . Esto fue robado de un comentario en PHP: Clases y objetos .


3

El soporte para clases anónimas ha estado disponible desde PHP 7.0, y es el análogo más cercano al ejemplo de JavaScript proporcionado en la pregunta.

<?php
$object = new class {
    var $p = "value";
    var $p1 = ["john", "johnny"];
};

echo $object->p1[1];

La declaración de visibilidad en las propiedades no se puede omitir (solo la utilicé varporque es más corta que public).

Al igual que JavaScript, también puede definir métodos para la clase:

<?php
$object = new class {
    var $p = "value";
    var $p1 = ["john", "johnny"];
    function foo() {return $this->p;}
};

echo $object->foo();

1

De la documentación de PHP, algunos ejemplos más:

<?php

$obj1 = new \stdClass; // Instantiate stdClass object
$obj2 = new class{}; // Instantiate anonymous class
$obj3 = (object)[]; // Cast empty array to object

var_dump($obj1); // object(stdClass)#1 (0) {}
var_dump($obj2); // object(class@anonymous)#2 (0) {}
var_dump($obj3); // object(stdClass)#3 (0) {}

?>

$ obj1 y $ obj3 son del mismo tipo, pero $ obj1! == $ obj3. Además, los tres json_encode () a un simple objeto JS {}:

<?php

echo json_encode([
    new \stdClass,
    new class{},
    (object)[],
]);

?>

Salidas:

[{},{},{}]

https://www.php.net/manual/en/language.types.object.php


0

Si desea crear un objeto (como en JavaScript) con propiedades dinámicas, sin recibir una advertencia de propiedad indefinida, cuando no ha establecido un valor en propiedad

class stdClass {

public function __construct(array $arguments = array()) {
    if (!empty($arguments)) {
        foreach ($arguments as $property => $argument) {
            if(is_numeric($property)):
                $this->{$argument} = null;
            else:
                $this->{$property} = $argument;
            endif;
        }
    }
}

public function __call($method, $arguments) {
    $arguments = array_merge(array("stdObject" => $this), $arguments); // Note: method argument 0 will always referred to the main class ($this).
    if (isset($this->{$method}) && is_callable($this->{$method})) {
        return call_user_func_array($this->{$method}, $arguments);
    } else {
        throw new Exception("Fatal error: Call to undefined method stdObject::{$method}()");
    }
}

public function __get($name){
    if(property_exists($this, $name)):
        return $this->{$name};
    else:
        return $this->{$name} = null;
    endif;
}

public function __set($name, $value) {
    $this->{$name} = $value;
}

}

$obj1 = new stdClass(['property1','property2'=>'value']); //assign default property
echo $obj1->property1;//null
echo $obj1->property2;//value

$obj2 = new stdClass();//without properties set
echo $obj2->property1;//null

0

¿Se puede aplicar esta misma técnica en el caso de PHP?

No, porque javascript utiliza prototipos / declaración directa de objetos, en PHP (y en muchos otros lenguajes OO), un objeto solo se puede crear a partir de una clase.

Entonces la pregunta es: ¿puedes crear una clase anónima?

Nuevamente, la respuesta es no: ¿cómo crearías una instancia de la clase sin poder hacer referencia a ella?


No necesita un nombre para crear una instancia de una clase anónima. Java: Object var = new Object() { ... };- C ++:class { ... } var;
TheOperator

1
Puede crear clases anónimas en PHP ahora.
Victor

0

Para quien quiere un objeto recursivo:

$o = (object) array(
    'foo' => (object) array(
        'sub' => '...'
    )
);

echo $o->foo->sub;

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.