두 개의 PHP 객체를 병합하는 가장 좋은 방법은 무엇입니까?
우리는 두 개의 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에서 테스트)
객체에 필드 만 포함되어 있으면 (메소드 없음) 다음과 같이 작동합니다.
$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;
}
}
}
행운을 빕니다.
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가 있습니다.
해결 방법 병합 된 주입에서 메소드와 속성을 모두 유지하려면 다음을 수행 할 수있는 결합기 클래스를 작성해야합니다.
- __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;
두 번째 객체를 첫 번째 객체의 속성에 연결합니다. 두 번째 객체가 함수 또는 메소드의 결과 인 경우 참조를 사용하십시오. 전의:
//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');
The \ArrayObject
class has the possibility to exchange the current array to disconnect the original reference. To do so, it comes with two handy methods: exchangeArray()
and getArrayCopy()
. The rest is plain simple array_merge()
of the provided object with the ArrayObject
s public properties:
class MergeBase extends ArrayObject
{
public final function merge( Array $toMerge )
{
$this->exchangeArray( array_merge( $this->getArrayCopy(), $toMerge ) );
}
}
The usage is as easy as this:
$base = new MergeBase();
$base[] = 1;
$base[] = 2;
$toMerge = [ 3,4,5, ];
$base->merge( $toMerge );
To merge any number of raw objects
function merge_obj(){
foreach(func_get_args() as $a){
$objects[]=(array)$a;
}
return (object)call_user_func_array('array_merge', $objects);
}
Here is a function that will flatten an object or array. Use this only if you are sure your keys are unique. If you have keys with the same name they will be overwritten. You will need to place this in a class and replace "Functions" with the name of your class. Enjoy...
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;
}
Let's keep it simple!
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);
}
If that doesn't answer your question, it will surely help towards the answer. Credit for the code above goes to myself :)
This snippet of code will recursively convert that data to a single type (array or object) without the nested foreach loops. Hope it helps someone!
Once an Object is in array format you can use array_merge and convert back to Object if you need to.
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;
}
}
Procedural way
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;
}
All credit goes to: Jason Oakley
참고URL : https://stackoverflow.com/questions/455700/what-is-the-best-method-to-merge-two-php-objects
'Programing' 카테고리의 다른 글
CSS를 사용하여 텍스트를 미러링 / 플립 할 수 있습니까? (0) | 2020.04.28 |
---|---|
<% = f.submit %>에 CSS 클래스 추가 (0) | 2020.04.28 |
.crt를 .pem로 변환하는 방법 (0) | 2020.04.27 |
strings.xml의 다른 문자열에서 하나의 문자열을 참조 하시겠습니까? (0) | 2020.04.27 |
날짜 시간 열에서 날짜를 선택하는 방법은 무엇입니까? (0) | 2020.04.27 |