Php объединить два объекта

Какой лучший способ объединить два объекта PHP?

У нас есть два объекта PHP5 и хотелось бы объединить содержимое одного во второе. Нет понятия подклассов между ними, поэтому решения, описанные в следующем разделе, не могут применяться. Как скопировать объект PHP в другой тип объекта

//We have this: $objectA->a; $objectA->b; $objectB->c; $objectB->d; //We want the easiest way to get: $objectC->a; $objectC->b; $objectC->c; $objectC->d; 
  • Это объекты, а не классы.
  • Объекты содержат довольно много полей, поэтому foreach будет довольно медленным.
  • До сих пор мы рассматриваем преобразование объектов A и B в массивы, а затем их слияние с помощью array_merge() перед тем, как преобразовать его в объект, но мы не можем сказать, что мы гордимся этим.

12 ответов

Если ваши объекты содержат только поля (без методов), это работает:

$obj_merged = (object) array_merge((array) $obj1, (array) $obj2); 

Это также работает, когда объекты имеют методы. (тестируется с PHP 5.3 и 5.6)

Вы также можете использовать array_merge_recursive для более глубокого копирования. Вы также можете быть заинтересованы в array_replace_recursive. Различия подробно объясняются здесь: brian.serveblog.net/2011/07/31/php-array_replace-vs-array_merge

Полученный в результате объект будет экземпляром класса stdclass . Хотя он в некотором смысле «работает» на объектах с методами, в этом случае он фактически разрушает объект (удаляя методы).

Это полезно для возврата нескольких наборов результатов в одной функции (и возврата только объекта с парами ключ-значение.)

Используя это для слияния объектов stdClass, возвращаемых при вызове json_decode (). Просто и работает. Спасибо, куча!

Это не будет работать, если в объекте есть целочисленный ключ. Рассмотрим следующий пример: $ arr1 = array (‘a’ => 9, ‘b’ => ‘asd’); $ arr2 = array (‘a’ => 10, ‘d’ => ‘qwert’, 0 => 100, 1 => 200, 4 => 400); $ arr3 = array_merge ($ arr1, $ arr2); echo (print_r ($ arr3, 1)); Фактический вывод: Array ([a] => 10 [b] => asd [d] => qwert [0] => 100 [1] => 200 [2] => 400) Требуемый вывод: Array ([a] => 10 [b] => asd [d] => qwert [0] => 100 [1] => 200 [4] => 400)

Читайте также:  Php редирект post запроса

Если ваши объекты содержат только поля (без методов), это работает:

$obj_merged = (object) array_merge((array) $obj1, (array) $obj2); 

Вы можете создать другой объект, который отправляет вызовы методам магии для основных объектов. Здесь, как вы бы справились с __get , но чтобы он полностью работал, вам придется переопределить все соответствующие магические методы. Вероятно, вы обнаружите синтаксические ошибки, так как я просто ввел его с головы.

class Compositor < private $obj_a; private $obj_b public function __construct($obj_a, $obj_b) < $this->obj_a = $obj_a; $this->obj_b = $obj_b; > public function __get($attrib_name) < if ($this->obj_a->$attrib_name) < return $this->obj_a->$attrib_name; > else < return $this->obj_b->$attrib_name; > > > 

Для полной реализации, вероятно, потребуется __isset (), __unset () и реализация интерфейса Interator.

Я бы отредактировал его комментарий, но вы не можете этого сделать. Я думаю, что он имеет в виду итератор

Мне очень нравится ваше решение, Аллен, но я боюсь, что это означает, что нам придется переписать все наше приложение, если мы решим его использовать.

foreach($objectA as $k => $v) $objectB->$k = $v; 

Это быстрее, чем принятый ответ в версиях PHP <7 (оценивается на 50% быстрее). Но в PHP>= 7 принятый ответ примерно на 400% быстрее. Смотрите здесь: sandbox.onlinephpfunctions.com/code/…

Я понимаю, что использование общих объектов [stdClass()] и отбрасывание их в виде массивов отвечает на вопрос, но я думал, что композитор был отличным ответом. Тем не менее, я чувствовал, что может использовать некоторые улучшения функций и может быть полезен для кого-то еще.

  • Укажите ссылку или клон
  • Укажите приоритет первой или последней записи
  • Несколько (более двух) объектов, объединяющихся с синтаксическим сходством с array_merge
  • Связывание метода: $obj- > f1() → f2() → f3().
  • Динамические композиты: $obj- > merge (. )/* работают здесь */$obj- > merge (. )
class Compositor < protected $composite = array(); protected $use_reference; protected $first_precedence; /** * __construct, Constructor * * Used to set options. * * @param bool $use_reference whether to use a reference (TRUE) or to copy the object (FALSE) [default] * @param bool $first_precedence whether the first entry takes precedence (TRUE) or last entry takes precedence (FALSE) [default] */ public function __construct($use_reference = FALSE, $first_precedence = FALSE) < // Use a reference $this->use_reference = $use_reference === TRUE ? TRUE : FALSE; $this->first_precedence = $first_precedence === TRUE ? TRUE : FALSE; > /** * Merge, used to merge multiple objects stored in an array * * This is used to *start* the merge or to merge an array of objects. * It is not needed to start the merge, but visually is nice. * * @param object[]|object $objects array of objects to merge or a single object * @return object the instance to enable linking */ public function & merge() < $objects = func_get_args(); // Each object foreach($objects as &$object) $this->with($object); // Garbage collection unset($object); // Return $this instance return $this; > /** * With, used to merge a singluar object * * Used to add an object to the composition * * @param object $object an object to merge * @return object the instance to enable linking */ public function & with(&$object) < // An object if(is_object($object)) < // Reference if($this->use_reference) < if($this->first_precedence) array_push($this->composite, $object); else array_unshift($this->composite, $object); > // Clone else < if($this->first_precedence) array_push($this->composite, clone $object); else array_unshift($this->composite, clone $object); > > // Return $this instance return $this; > /** * __get, retrieves the psudo merged object * * @param string $name name of the variable in the object * @return mixed returns a reference to the requested variable * */ public function & __get($name) < $return = NULL; foreach($this->composite as &$object) < if(isset($object->$name)) < $return =& $object->$name; break; > > // Garbage collection unset($object); return $return; > > 
$obj = new Compositor(use_reference, first_precedence); $obj->merge([object $object [, object $object [, object $. ]]]); $obj->with([object $object]); 
$obj1 = new stdClass(); $obj1->a = 'obj1:a'; $obj1->b = 'obj1:b'; $obj1->c = 'obj1:c'; $obj2 = new stdClass(); $obj2->a = 'obj2:a'; $obj2->b = 'obj2:b'; $obj2->d = 'obj2:d'; $obj3 = new Compositor(); $obj3->merge($obj1, $obj2); $obj1->c = '#obj1:c'; var_dump($obj3->a, $obj3->b, $obj3->c, $obj3->d); // obj2:a, obj2:b, obj1:c, obj2:d $obj1->c; $obj3 = new Compositor(TRUE); $obj3->merge($obj1)->with($obj2); $obj1->c = '#obj1:c'; var_dump($obj3->a, $obj3->b, $obj3->c, $obj3->d); // obj1:a, obj1:b, obj1:c, obj2:d $obj1->c = 'obj1:c'; $obj3 = new Compositor(FALSE, TRUE); $obj3->with($obj1)->with($obj2); $obj1->c = '#obj1:c'; var_dump($obj3->a, $obj3->b, $obj3->c, $obj3->d); // obj1:a, obj1:b, #obj1:c, obj2:d $obj1->c = 'obj1:c'; 

Просто для того, чтобы указать: передача по времени вызова была помечена как устаревшая в PHP 5.3.0 и удалена в PHP 5.4.0 (что привело к фатальной ошибке). Чтобы исправить проблему: Замените foreach($objects as &$object) $this->with(&$object); с foreach($objects as &$object) $this->with($object); исправляет проблему. Источник: [ php.net/manual/en/language.references.pass.php]

Читайте также:  Menu bar html template

Дополнительно: if($this->first_precedence) array_push($this->composite, &$object); else array_unshift($this->composite, &$object); следует заменить на if($this->first_precedence) array_push($this->composite, $object); else array_unshift($this->composite, $object);

Итак, чтобы суммировать ваши комментарии, удалите амперсанд (&) из $ object изнутри: foreach (первый комментарий) . array_push, array_unshift (второй комментарий)

Источник

Оцените статью