Создание анонимных объектов в php

142

Как мы знаем, создавать анонимные объекты в JavaScript очень просто, как в приведенном ниже коде:

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

alert(object.p1[1]);

Выход:

an alert is raised with value "johnny"

Можно ли применить эту же технику в PHP? Можем ли мы создавать анонимные объекты в PHP?

Суджит Агарвал
источник
1
Примечание: это старый вопрос, поэтому принятый ответ устарел. Эта запрошенная функция теперь добавлена ​​в PHP 7. См. Ответ @ Rizier123 ниже.
Simba
@Simba - Спасибо, что указали на это. Хотели бы вы опубликовать ответ на StackOverflow здесь, на этой странице, чтобы помочь будущим посетителям?
Суджит Агарвал,
1
Мне не нужно; с этой информацией уже есть ответ (см. ниже, автор @ Rizier123).
Simba

Ответы:

41

Прошло несколько лет, но я думаю, что мне нужно постоянно обновлять информацию!

Начиная с PHP 7 появилась возможность создавать анонимные классы, поэтому вы можете делать такие вещи:

<?php

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

    var_dump($child instanceof Foo); // true

?>

Подробнее об этом вы можете прочитать в инструкции

Но я не знаю, насколько это похоже на JavaScript, поэтому между анонимными классами в JavaScript и PHP могут быть некоторые различия.

Rizier123
источник
@risyasin Спасибо, обновил ответ и поместил в него ссылку на руководство.
Rizier123
Отметьте свой ответ как правильный, чтобы не отставать от последних изменений в php7. Спасибо @ Rizier123
Агарвал
4
Это интересно, но на самом деле это не решает вопрос, поскольку OP спрашивал об удобном способе инициализации объекта с различными членами без создания класса. Я не уверен, можно ли использовать анонимные классы в php для этого, и если это возможно, вы не объяснили, как это сделать.
amh15,
229

«Анонимный» - неправильная терминология, когда речь идет об объектах. Лучше было бы сказать «объект анонимного типа », но это не относится к PHP.

Все объекты в PHP имеют класс. Класс "по умолчанию" есть stdClass, и вы можете создавать его объекты следующим образом:

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

Вы также можете воспользоваться преобразованием массива в объект для более удобного синтаксиса:

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

Однако имейте в виду, что приведение массива к объекту может дать «интересные» результаты для тех ключей массива, которые не являются допустимыми именами переменных PHP - например, вот мой ответ, который показывает, что происходит, когда ключи начинаются с цифр.

Джон
источник
1
Могу ли я также нажать многозначный массив?
Суджит Агарвал
2
@CodingFreak: вы можете, но : если массив содержит подмассивы, и вы хотите, чтобы они также были объектами, вам нужно будет явно преобразовать каждый объект в объект.
Джон
21

Да, это возможно! Используя этот простой класс анонимного объекта PHP . Как это работает:

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

Конечно, этот объект является экземпляром AnObjкласса, поэтому на самом деле он не анонимен, но он позволяет определять методы на лету, как это делает JavaScript.

Михайлов
источник
Вы можете использовать create_function для имитации анонимной функции.
Mihailoff
Я думаю, ему просто нужен изящный способ инициализировать объект stdClass некоторыми значениями. Сможете ли вы сделать это с вашим подходом?
amh15
19

До недавнего времени я создавал объекты именно так на лету.

$someObj = json_decode("{}");

Затем:

$someObj->someProperty = someValue;

Но теперь я иду с:

$someObj = (object)[];

Тогда как раньше:

$someObj->someProperty = someValue;

Конечно, если вы уже знаете свойства и значения, вы можете установить их внутри, как уже упоминалось:

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

NB: я не знаю, на каких версиях PHP это работает, поэтому вам нужно помнить об этом. Но я думаю, что первый подход (который также короткий, если нет свойств, которые нужно установить при создании) должен работать для всех версий, в которых есть json_encode / json_decode.

Зукс
источник
1
Чем это отличается от перехода на $ someObj = new \ stdClass ()?
JamesNZ 05
9

Преобразовать массив в объект (но это не рекурсивно для дочерних элементов):

$obj = (object)  ['myProp' => 'myVal'];
Т. Тодуа
источник
7

Если вы хотите имитировать JavaScript, вы можете создать класс Objectи, таким образом, получить такое же поведение. Конечно, это уже не совсем анонимно, но это будет работать.

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

Это выведет элемент 2 . Это было украдено из комментария к PHP: классы и объекты .

кба
источник
3

Поддержка анонимных классов доступна с PHP 7.0 и является ближайшим аналогом примера JavaScript, приведенного в вопросе.

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

echo $object->p1[1];

Объявление видимости свойств не может быть опущено (я просто использовал, varпотому что он короче, чем public.)

Как и в JavaScript, вы также можете определять методы для класса:

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

echo $object->foo();
miken32
источник
1

Из документации PHP еще несколько примеров:

<?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 и $ obj3 одного типа, но $ obj1! == $ obj3. Кроме того, все три будут json_encode () для простого объекта JS {}:

<?php

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

?>

Выходы:

[{},{},{}]

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

Иван Ивкович
источник
0

Если вы хотите создать объект (например, в javascript) с динамическими свойствами, не получая предупреждения о неопределенном свойстве, когда вы не установили значение для свойства

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
fredtma
источник
0

Можно ли применить эту же технику в случае PHP?

Нет - поскольку javascript использует прототипы / прямое объявление объектов - в PHP (и многих других объектно-ориентированных языках) объект может быть создан только из класса.

Возникает вопрос: можете ли вы создать анонимный класс.

И снова ответ - нет - как бы вы создали экземпляр класса, не имея возможности ссылаться на него?

symcbean
источник
Вам не нужно имя для создания экземпляра анонимного класса. Java: Object var = new Object() { ... };- C ++:class { ... } var;
TheOperator
1
Теперь вы можете создавать анонимные классы в PHP.
Виктор
0

Для тех, кто хочет рекурсивный объект:

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

echo $o->foo->sub;
Джонатас Уокер
источник