我们有两个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()将它们合并,但如果这样我们不能说我们感到自豪。


当前回答

让我们保持简单!

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);
}

如果这不能回答你的问题,它肯定会帮助你找到答案。 以上代码归我所有:)

其他回答

如果你的对象只包含字段(没有方法),这是可行的:

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

当对象具有方法时,这实际上也适用。(使用PHP 5.3和5.6进行测试)

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

一旦一个对象变成数组格式,你就可以使用array_merge并在需要的时候转换回Object。

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;
}

所有功劳归于杰森·奥克利

为了保存合并对象的方法和属性,可以创建一个组合子类

在__construct上取任意数量的对象 使用__call访问任何方法 使用__get访问任何属性


class combinator{
function __construct(){       
    $this->melt =  array_reverse(func_get_args());
      // array_reverse is to replicate natural overide
}
public function __call($method,$args){
    forEach($this->melt as $o){
        if(method_exists($o, $method)){
            return call_user_func_array([$o,$method], $args);
            //return $o->$method($args);
            }
        }
    }
public function __get($prop){
        foreach($this->melt as $o){
          if(isset($o->$prop))return $o->$prop;
        }
        return 'undefined';
    } 
}

简单的用

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;

这是一个将对象或数组平展的函数。只有在确定密钥是唯一的情况下才使用此方法。如果有相同名称的键,它们将被覆盖。您需要将其放在一个类中,并将“Functions”替换为您的类名。享受……

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;
}

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

//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');