Tworzenie anonimowych obiektów w php


141

Jak wiemy, tworzenie anonimowych obiektów w JavaScript jest łatwe, jak w poniższym kodzie:

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

alert(object.p1[1]);

Wynik:

an alert is raised with value "johnny"

Czy tę samą technikę można zastosować w PHP? Czy możemy tworzyć anonimowe obiekty w PHP?


1
Uwaga: to jest stare pytanie, więc zaakceptowana odpowiedź jest nieaktualna. Ta funkcja, o którą proszono, została teraz dodana do PHP 7. Zobacz odpowiedź poniżej @ Rizier123.
Simba

@Simba - Dziękuję za zwrócenie uwagi. Czy chcesz opublikować odpowiedź na StackOverflow tutaj, na tej stronie, aby pomóc przyszłym odwiedzającym?
Sujit Agarwal

1
Nie potrzebuję; jest już odpowiedź z tymi informacjami (patrz poniżej, @ Rizier123).
Simba,

Odpowiedzi:


40

Minęło już kilka lat, ale myślę, że muszę aktualizować informacje!

Od PHP 7 możliwe było tworzenie anonimowych klas, więc możesz robić takie rzeczy:

<?php

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

    var_dump($child instanceof Foo); // true

?>

Możesz przeczytać więcej na ten temat w instrukcji

Ale nie wiem, jak podobny jest do JavaScript, więc może występować kilka różnic między klasami anonimowymi w JavaScript i PHP.


@risyasin Dzięki, zaktualizowałem odpowiedź i umieść w niej link do instrukcji.
Rizier123

Oznaczanie odpowiedzi jako poprawnej, aby być na bieżąco z najnowszymi zmianami w php7. Dzięki @ Rizier123
Sujit Agarwal

3
Jest to interesujące, ale tak naprawdę nie rozwiązuje tego pytania, ponieważ OP pytał o wygodny sposób inicjalizacji obiektu z różnymi członkami bez tworzenia klasy. Nie jestem pewien, czy można to zrobić za pomocą anonimowych klas w php, a jeśli to możliwe, nie wyjaśniłeś, jak to zrobić.
amh15

228

„Anonimowy” nie jest poprawną terminologią w odniesieniu do przedmiotów. Lepiej byłoby powiedzieć „obiekt typu anonimowego ”, ale nie dotyczy to PHP.

Wszystkie obiekty w PHP mają klasę. Klasą „domyślną” jest stdClassi możesz tworzyć z niej obiekty w następujący sposób:

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

Możesz także skorzystać z rzutowania tablicy na obiekt, aby uzyskać wygodniejszą składnię:

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

Należy jednak pamiętać, że rzutowanie tablicy na obiekt może przynieść „interesujące” wyniki dla tych kluczy tablic, które nie są prawidłowymi nazwami zmiennych PHP - na przykład, oto moja odpowiedź, która pokazuje, co się dzieje, gdy klucze zaczynają się od cyfr.


1
czy mogę również wypchnąć tablicę o wielu wartościach?
Sujit Agarwal

2
@CodingFreak: Możesz, ale : jeśli tablica zawiera pod-tablice i chcesz je również jako obiekty, będziesz musiał jawnie rzutować każdą z nich na obiekt.
Jon

21

Tak to mozliwe! Korzystanie z tej prostej klasy obiektu anonimowego PHP . Jak to działa:

// 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"

Oczywiście ten obiekt jest instancją AnObjklasy, więc nie jest tak naprawdę anonimowy, ale umożliwia definiowanie metod w locie, tak jak robi to JavaScript.


Możesz użyć funkcji create_function do emulacji funkcji anonimowej.
Mihailoff

Myślę, że po prostu chciał zgrabnego sposobu zainicjowania obiektu stdClass z pewnymi wartościami. Czy możesz to zrobić ze swoim podejściem?
amh15

18

W ten sposób do niedawna tworzyłem obiekty w locie.

$someObj = json_decode("{}");

Następnie:

$someObj->someProperty = someValue;

Ale teraz idę z:

$someObj = (object)[];

Wtedy jak poprzednio:

$someObj->someProperty = someValue;

Oczywiście, jeśli znasz już właściwości i wartości, możesz je ustawić w środku, jak wspomniano:

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

NB: Nie wiem, na jakich wersjach PHP to działa, więc musisz o tym pamiętać. Ale myślę, że pierwsze podejście (które jest również krótkie, jeśli nie ma właściwości do ustawienia podczas budowy) powinno działać dla wszystkich wersji, które mają json_encode / json_decode


1
Czym się to różni od $ someObj = new \ stdClass ()?
JamesNZ

9

Konwertuj tablicę na obiekt (ale to nie jest rekurencyjne dla podrzędnych):

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

7

Jeśli chcesz naśladować JavaScript, możesz utworzyć klasę Objecti uzyskać takie samo zachowanie. Oczywiście nie jest to już całkiem anonimowe, ale zadziała.

<?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];
?>

To da element 2 . Zostało to skradzione z komentarza do PHP: Classes and Objects .


3

Obsługa klas anonimowych jest dostępna od PHP 7.0 i jest najbliższym odpowiednikiem przykładu JavaScript przedstawionego w pytaniu.

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

echo $object->p1[1];

Nie można pominąć deklaracji widoczności właściwości (użyłem tylko vardlatego, że jest krótsza niż public).

Podobnie jak JavaScript, możesz również zdefiniować metody dla klasy:

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

echo $object->foo();

1

Z dokumentacji PHP kilka więcej przykładów:

<?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 i $ obj3 są tego samego typu, ale $ obj1! == $ obj3. Ponadto wszystkie trzy wyślą json_encode () do prostego obiektu JS {}:

<?php

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

?>

Wyjścia:

[{},{},{}]

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


0

Jeśli chcesz stworzyć obiekt (jak w javascript) z dynamicznymi właściwościami, bez otrzymywania ostrzeżenia o niezdefiniowanej właściwości, gdy nie ustawiłeś wartości na property

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

Czy tę samą technikę można zastosować w przypadku PHP?

Nie - ponieważ javascript używa prototypów / bezpośredniej deklaracji obiektów - w PHP (i wielu innych językach OO) obiekt można stworzyć tylko z klasy.

Powstaje więc pytanie - czy możesz stworzyć anonimową klasę.

Znowu odpowiedź brzmi nie - w jaki sposób utworzyłbyś instancję klasy bez możliwości odniesienia się do niej?


Nie potrzebujesz nazwy, aby utworzyć instancję klasy anonimowej. Java: Object var = new Object() { ... };- C ++:class { ... } var;
TheOperator

1
Możesz teraz tworzyć anonimowe klasy w PHP.
Victor

0

Dla tego, kto chce obiektu rekurencyjnego:

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

echo $o->foo->sub;

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.