우리는 두 개의 PHP5 객체를 가지고 있으며 하나의 내용을 두 번째로 병합하고 싶습니다. 하위 클래스에 대한 개념이 없으므로 다음 주제에서 설명하는 솔루션을 적용 할 수 없습니다.
//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 () 를 사용하여 병합하는 것을 고려 하지만 이것이 자랑 스럽다고 말할 수는 없습니다.
답변
객체에 필드 만 (메소드 없음) 포함되어 있으면 다음과 같이 작동합니다.
$obj_merged = (object) array_merge((array) $obj1, (array) $obj2);
이것은 실제로 객체에 메소드가있는 경우에도 작동합니다. (PHP 5.3 및 5.6에서 테스트)
답변
매직 메서드에 대한 호출을 기본 개체에 디스패치하는 다른 개체를 만들 수 있습니다. 처리 방법은 다음과 __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;
답변
제네릭 객체 [stdClass ()]를 사용하고 배열로 캐스팅하면 질문에 대한 답변을 얻을 수 있지만 컴포 지터가 큰 답변이라고 생각합니다. 그러나 일부 기능 향상을 사용할 수 있으며 다른 사람에게 유용 할 수 있다고 생각했습니다.
풍모:
- 참조 또는 복제본 지정
- 우선 순위를 지정할 첫 번째 또는 마지막 항목을 지정하십시오.
- array_merge와 구문이 유사한 다중 (2 개 이상) 객체 병합
- 메소드 연결 : $ 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';
답변
객체 A와 B가 있다고 생각하는 매우 간단한 솔루션 :
foreach($objB AS $var=>$value){
$objA->$var = $value;
}
그게 다야. 이제 objB의 모든 값을 가진 objA가 있습니다.
답변
\ArrayObject
클래스 가능성 갖는 교환 원래 분리 현재 배열을 참조 . 이렇게하려면 두 개의 편리한 방법을 함께 제공 : exchangeArray()
와 getArrayCopy()
. 나머지는 s 공개 속성으로 array_merge()
제공된 객체의 단순 ArrayObject
합니다.
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 );
답변
솔루션 병합 된 주입에서 메서드와 속성을 모두 유지하려면 다음을 수행 할 수있는 결합기 클래스를 만드는 것입니다.
- __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;
