Care este cea mai bună metodă de a îmbina două obiecte PHP?

Avem două PHP5 obiecte și-ar dori să fuzioneze conținutul de unul în cel de-al doilea. Nu există noțiunea de subclase între ele astfel încât soluțiile descrise în următoarele subiect nu se poate aplica.

Cum ai copia un PHP obiect într-un alt tip de obiect

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

Observații:

  • Acestea sunt obiecte, nu pe clase.
  • Obiectele conține destul de o mulțime de domenii, deci un foreach ar fi destul de lent.
  • Până în prezent avem în vedere transformarea obiecte a și B în matrice, apoi fuzionează le folosesc array_merge() înainte de a re-transformarea într-un obiect, dar putem't spune că suntem mândri daca acest lucru.
Comentarii la întrebare (1)
Soluția

Dacă obiectele conține doar câmpuri (metode), acest lucru funcționează:

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

Acest fapt, de asemenea, funcționează atunci când obiectele au metode. (testat cu PHP 5.3 și 5.6)

Comentarii (8)

Dacă obiectele conține doar câmpuri (metode), acest lucru funcționează:

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

Ai putea crea un alt obiect care expedieri apeluri la magie metode de bază de obiecte. Aici's cum te-ai'd ocup `__a obține, dar să-l de lucru pe deplin te'd trebuie să suprascrie toate relevante magic metode. Te'll găsi, probabil, erori de sintaxă când am intrat doar de pe partea de sus a capul meu.

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

Noroc.

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

Am înțeles că, folosind generic de obiecte [stdClass()] și turnare-le ca matrice răspunde la întrebare, dar m-am gândit Compozitorul a fost un răspuns bun. Totuși, am simțit că ar putea utiliza unele îmbunătățiri și ar putea fi util pentru altcineva.

Caracteristici:

  • Specifica referință sau clona
  • Se specifică prima sau ultima intrare să aibă prioritate
  • Multiple (mai mult de două) obiect care fuzionează cu sintaxa asemănare cu array_merge
  • Metoda de legătură: $obj->f1()->f2()->f3()...
  • Dinamic compozite: $obj->îmbinare(...) / munca aici / $obj->îmbinare(...)

Cod:

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

Utilizare:

$obj = new Compositor(use_reference, first_precedence);
$obj->merge([object $object [, object $object [, object $...]]]);
$obj->with([object $object]);

Exemplu:

$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';
Comentarii (8)

O soluție foarte simplă, având în vedere că au de obiect a și B:

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

Ca's toate. Acum aveți objA cu toate valorile din objB.

Comentarii (2)

o soluție Pentru a păstra,ambele metode și proprietăți din fuzionat onjects este de a crea un combinator clasă, care pot

  • ia orice număr de obiecte pe __construct
  • acces orice metodă care utilizează __suni
  • accsess orice proprietate utilizând __se

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

utilizare simplă

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;
Comentarii (2)

Pentru a fuziona orice număr de prime obiecte

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

Anii \ArrayObject clasa are posibilitatea de a _exchange_ matrice curent pentru a deconecta original _reference_. Pentru a face acest lucru, acesta vine cu două îndemână metode:exchangeArray () " și " getArrayCopy(). Restul este simpluarray_merge()a oferit obiect cuArrayObject publice proprietăți:

class MergeBase extends ArrayObject
{
     public final function merge( Array $toMerge )
     {
          $this->exchangeArray( array_merge( $this->getArrayCopy(), $toMerge ) );
     }
 }

Utilizarea este la fel de ușor ca asta:

 $base = new MergeBase();

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

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

 $base->merge( $toMerge );
Comentarii (1)

Mi-ar merge cu legarea cel de-al doilea obiect într-o proprietate de primul obiect. Dacă cel de-al doilea obiect este rezultatul de o funcție sau metodă, utilizați referințe. Ex:

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

Las's păstrați-l simplu!

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

Dacă asta nu't răspunde la întrebarea dumneavoastră, aceasta va ajuta cu siguranță spre răspunsul. Credit pentru codul de mai sus merge la mine :)

Comentarii (0)

Aici este o funcție care va aplatiza un obiect sau un array. Utilizați acest lucru numai dacă sunteți sigur că cheile sunt unice. Dacă aveți cheile cu același nume vor fi suprascrise. Veți avea nevoie pentru a plasa acest lucru într-o clasă și înlocuiți "Funcții" cu numele clasei. Bucurați-vă de...

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;
}
Comentarii (0)

Acest fragment de cod va recursiv converti datele la un singur tip (array sau object) fără imbricate foreach bucle. Sper sa ajute pe cineva!

Odată ce un Obiect este în format matrice puteți utiliza array_merge și de a converti înapoi la Obiect, dacă aveți nevoie să.

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

Procedurale mod

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

Toate de credit merge la: Jason Oakley

Comentarii (0)