合并两个PHP对象的最佳方法是什么?

合并两个PHP对象的最佳方法是什么?,php,oop,object,Php,Oop,Object,我们有两个PHP5对象,希望将其中一个对象的内容合并到第二个对象中。它们之间没有子类的概念,因此以下主题中描述的解决方案无法应用 备注: 这些是对象,而不是类 对象包含相当多的字段,因此foreach将非常慢 到目前为止,我们考虑将对象A和B转换成数组,然后在重新转换为对象之前使用 ARARY-MYGER()/强>合并它们,但是我们不能说我们感到骄傲。 您可以创建另一个对象,将对魔术方法的调用分派给底层对象。下面是您如何处理\uuu get,但要让它完全工作,您必须覆盖所有相关的魔术方法。你

我们有两个PHP5对象,希望将其中一个对象的内容合并到第二个对象中。它们之间没有子类的概念,因此以下主题中描述的解决方案无法应用

备注:

  • 这些是对象,而不是类

  • 对象包含相当多的字段,因此foreach将非常慢
  • 到目前为止,我们考虑将对象A和B转换成数组,然后在重新转换为对象之前使用<强> ARARY-MYGER()/强>合并它们,但是我们不能说我们感到骄傲。
您可以创建另一个对象,将对魔术方法的调用分派给底层对象。下面是您如何处理
\uuu 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;
    }
  }
}

祝你好运。

这里有一个函数可以展平对象或数组。仅当您确定密钥是唯一的时才使用此选项。如果您有同名的密钥,它们将被覆盖。您需要将其放在类中,并用类的名称替换“函数”。享受

foreach($objectA as $k => $v) $objectB->$k = $v;
function flatten($array, $preserve_keys=1, &$out = array(), $isobject=0) {
        # Flatten a multidimensional array to one dimension, optionally preserving keys.
        #
        # $array - the array to flatten
        # $preserve_keys - 0 (default) to not preserve keys, 1 to preserve string keys only, 2 to preserve all keys
        # $out - internal use argument for recursion
        # $isobject - is internally set in order to remember if we're using an object or array
        if(is_array($array) || $isobject==1)
        foreach($array as $key => $child)
            if(is_array($child))
                $out = Functions::flatten($child, $preserve_keys, $out, 1); // replace "Functions" with the name of your class
            elseif($preserve_keys + is_string($key) > 1)
                $out[$key] = $child;
            else
                $out[] = $child;

        if(is_object($array) || $isobject==2)
        if(!is_object($out)){$out = new stdClass();}
        foreach($array as $key => $child)
            if(is_object($child))
                $out = Functions::flatten($child, $preserve_keys, $out, 2); // replace "Functions" with the name of your class
            elseif($preserve_keys + is_string($key) > 1)
                $out->$key = $child;
            else
                $out = $child;

        return $out;
}

我知道使用泛型对象[stdClass()]并将它们转换为数组可以回答这个问题,但我认为合成器是一个很好的答案。但我觉得它可以使用一些功能增强,可能对其他人有用

特点:

  • 指定引用或克隆
  • 指定第一个或最后一个优先项
  • 多个(两个以上)对象合并,语法与数组\u merge相似
  • 方法链接:$obj->f1()->f2()->f3()
  • 动态组合:$obj->merge(…)/*在此处工作*/$obj->merge(…)
代码:

用法:

$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和5.6进行测试)

考虑到对象A和B,这是一个非常简单的解决方案:

foreach($objB AS $var=>$value){
    $objA->$var = $value;
}

就这些。您现在拥有了objB中所有值的objA。

我会将第二个对象链接到第一个对象的属性中。如果第二个对象是函数或方法的结果,请使用引用。例:

//Not the result of a method
$obj1->extra = new Class2();

//The result of a method, for instance a factory class
$obj1->extra =& Factory::getInstance('Class2');

\ArrayObject
类可以交换当前数组以断开原始引用。为此,它提供了两个方便的方法:
exchangeArray()
getArrayCopy()
。其余的是所提供对象的简单的
array\u merge()
,具有
ArrayObject
s公共属性:

class MergeBase extends ArrayObject
{
     public final function merge( Array $toMerge )
     {
          $this->exchangeArray( array_merge( $this->getArrayCopy(), $toMerge ) );
     }
 }
使用方法非常简单,如下所示:

 $base = new MergeBase();

 $base[] = 1;
 $base[] = 2;

 $toMerge = [ 3,4,5, ];

 $base->merge( $toMerge );
让我们保持简单

function copy_properties($from, $to, $fields = null) {
    // copies properties/elements (overwrites duplicates)
    // can take arrays or objects 
    // if fields is set (an array), will only copy keys listed in that array
    // returns $to with the added/replaced properties/keys
    $from_array = is_array($from) ? $from : get_object_vars($from);
    foreach($from_array as $key => $val) {
        if(!is_array($fields) or in_array($key, $fields)) {
            if(is_object($to)) {
                $to->$key = $val;
            } else {
                $to[$key] = $val;
            }
        }
    }
    return($to);
}
如果这不能回答你的问题,那肯定会有助于找到答案。
上面的代码归功于我自己:)

要保留合并对象中的方法和属性,一个解决方案是创建一个可以

  • 在_构造上获取任意数量的对象
  • 使用_调用访问任何方法
  • 使用uuu get访问任何属性


简单使用

class c1{
    public $pc1='pc1';
    function mc1($a,$b){echo __METHOD__." ".($a+$b);}
}
class c2{
    public $pc2='pc2';
    function mc2(){echo __CLASS__." ".__METHOD__;}
}

$comb=new combinator(new c1, new c2);

$comb->mc1(1,2);
$comb->non_existing_method();  //  silent
echo $comb->pc2;

合并任意数量的原始对象

function merge_obj(){
    foreach(func_get_args() as $a){
        $objects[]=(array)$a;
    }
    return (object)call_user_func_array('array_merge', $objects);
}

这段代码将递归地将数据转换为单一类型(数组或对象),而不使用嵌套的foreach循环。希望它能帮助别人

一旦一个对象是数组格式的,您可以使用array\u merge并在需要时转换回对象

abstract class Util {
    public static function object_to_array($d) {
        if (is_object($d))
            $d = get_object_vars($d);

        return is_array($d) ? array_map(__METHOD__, $d) : $d;
    }

    public static function array_to_object($d) {
        return is_array($d) ? (object) array_map(__METHOD__, $d) : $d;
    }
}
程序方式

function object_to_array($d) {
    if (is_object($d))
        $d = get_object_vars($d);

    return is_array($d) ? array_map(__FUNCTION__, $d) : $d;
}

function array_to_object($d) {
    return is_array($d) ? (object) array_map(__FUNCTION__, $d) : $d;
}

所有的功劳都归于:Jason Oakley

完整的实现可能需要_isset(),_unset()和实现Interator接口。@porneL:Interator接口是什么?我想编辑他的评论,但你不能这么做。我想他的意思和你的解决方案非常相似,Allain,但我担心这意味着如果我们决定使用它,我们必须重写整个应用程序。好的。。。然后选择不需要完全重写的方式。“对象包含相当多的字段,因此foreach将非常慢。”-计算机非常快,“非常慢”通常足够快。为什么不直接这样做:$objB=$objA;您还可以使用array\u merge\u recursive来实现深度复制行为。您可能还对数组替换递归感兴趣。这里详细解释了这些区别:由此产生的对象将是
stdclass
的一个实例。虽然它在某种意义上对具有方法的对象“有效”,但在这种情况下(通过删除方法),它实际上会破坏对象。这对于在单个函数中返回多个结果集(并且仅返回具有键值对的对象)很有用。如果对象中存在整数键,则这将不起作用。考虑下面的例子:$ARL1=数组(‘a’=>9,‘b’=>‘asd’);$arr2=数组('a'=>10,'d'=>qwert',0=>100,1=>200,4=>400)$arr3=数组合并($arr1,$arr2);echo(print_r($arr3,1));实际输出:数组([a]=>10[b]=>asd[d]=>qwert[0]=>100[1]=>200[2]=>400)期望输出:数组([a]=>10[b]=>asd[d]=>qwert[0]=>100[1]=>200[4]=>400)这是我的答案还是已经发布了几个月的答案的逐字副本?需要指出的是:调用时间传递引用在PHP5.3.0中被标记为不推荐,在PHP5.4.0中被删除(导致引发致命错误)。要更正此问题,请将
foreach($objects as&$object)$this->替换为(&$object)
with
foreach($objects as&$object)$this->with($object)更正此问题。来源:[另外:
if($this->first\u priority)array\u push($this->composite,&$object);else array\u unshift($this->composite,&$object);
应替换为
if($this->first\u priority)array\u push($this->composite,&$object);else array\u unshift($this->composite,&$object);
因此要总结您的评论,请删除和(&)from$object inside:foreach(第一条评论)…数组_push,数组_unshift(第二条评论)@Chri
class c1{
    public $pc1='pc1';
    function mc1($a,$b){echo __METHOD__." ".($a+$b);}
}
class c2{
    public $pc2='pc2';
    function mc2(){echo __CLASS__." ".__METHOD__;}
}

$comb=new combinator(new c1, new c2);

$comb->mc1(1,2);
$comb->non_existing_method();  //  silent
echo $comb->pc2;
function merge_obj(){
    foreach(func_get_args() as $a){
        $objects[]=(array)$a;
    }
    return (object)call_user_func_array('array_merge', $objects);
}
abstract class Util {
    public static function object_to_array($d) {
        if (is_object($d))
            $d = get_object_vars($d);

        return is_array($d) ? array_map(__METHOD__, $d) : $d;
    }

    public static function array_to_object($d) {
        return is_array($d) ? (object) array_map(__METHOD__, $d) : $d;
    }
}
function object_to_array($d) {
    if (is_object($d))
        $d = get_object_vars($d);

    return is_array($d) ? array_map(__FUNCTION__, $d) : $d;
}

function array_to_object($d) {
    return is_array($d) ? (object) array_map(__FUNCTION__, $d) : $d;
}