@@ -43,32 +43,34 @@ class ObjectMerge
43
43
const OBJECT_T = 'object ' ;
44
44
45
45
/** @var bool */
46
- private static $ _recurse ;
46
+ private static $ _recursive ;
47
47
/** @var int */
48
48
private static $ _opts ;
49
+ /** @var callable */
50
+ private static $ _cb ;
49
51
50
52
/** @var int */
51
53
private static $ _depth = -1 ;
52
54
/** @var array */
53
55
private static $ _context = [];
54
56
55
57
// list of types considered "simple"
56
- private static $ _SIMPLE_TYPES = array (
58
+ private static $ _SIMPLE_TYPES = [
57
59
self ::NULL_T ,
58
60
self ::RESOURCE_T ,
59
61
self ::STRING_T ,
60
62
self ::BOOLEAN_T ,
61
63
self ::INTEGER_T ,
62
64
self ::DOUBLE_T
63
- ) ;
65
+ ] ;
64
66
65
67
/**
66
68
* @param stdClass ...$objects
67
69
* @return stdClass|null
68
70
*/
69
71
public function __invoke (stdClass ...$ objects )
70
72
{
71
- return self ::_doMerge (false , self ::DEFAULT_OPTS , $ objects );
73
+ return self ::_doMerge (false , self ::DEFAULT_OPTS , null , $ objects );
72
74
}
73
75
74
76
/**
@@ -77,7 +79,7 @@ public function __invoke(stdClass ...$objects)
77
79
*/
78
80
public static function merge (stdClass ...$ objects )
79
81
{
80
- return self ::_doMerge (false , self ::DEFAULT_OPTS , $ objects );
82
+ return self ::_doMerge (false , self ::DEFAULT_OPTS , null , $ objects );
81
83
}
82
84
83
85
/**
@@ -86,7 +88,7 @@ public static function merge(stdClass ...$objects)
86
88
*/
87
89
public static function mergeRecursive (stdClass ...$ objects )
88
90
{
89
- return self ::_doMerge (true , self ::DEFAULT_OPTS , $ objects );
91
+ return self ::_doMerge (true , self ::DEFAULT_OPTS , null , $ objects );
90
92
}
91
93
92
94
/**
@@ -96,7 +98,7 @@ public static function mergeRecursive(stdClass ...$objects)
96
98
*/
97
99
public static function mergeOpts ($ opts , stdClass ...$ objects )
98
100
{
99
- return self ::_doMerge (false , $ opts , $ objects );
101
+ return self ::_doMerge (false , $ opts , null , $ objects );
100
102
}
101
103
102
104
/**
@@ -106,7 +108,69 @@ public static function mergeOpts($opts, stdClass ...$objects)
106
108
*/
107
109
public static function mergeRecursiveOpts ($ opts , stdClass ...$ objects )
108
110
{
109
- return self ::_doMerge (true , $ opts , $ objects );
111
+ return self ::_doMerge (true , $ opts , null , $ objects );
112
+ }
113
+
114
+ /**
115
+ * @param int $opts
116
+ * @param callable $cb
117
+ * @param stdClass ...$objects
118
+ * @return stdClass
119
+ */
120
+ public static function mergeCallback ($ opts , $ cb , stdClass ...$ objects )
121
+ {
122
+ return self ::_doMerge (false , $ opts , $ cb , $ objects );
123
+ }
124
+
125
+ /**
126
+ * @param int $opts
127
+ * @param callable $cb
128
+ * @param stdClass ...$objects
129
+ * @return stdClass
130
+ */
131
+ public static function mergeRecursiveCallback ($ opts , $ cb , stdClass ...$ objects )
132
+ {
133
+ return self ::_doMerge (true , $ opts , $ cb , $ objects );
134
+ }
135
+
136
+ /**
137
+ * @return ObjectMergeState
138
+ */
139
+ public static function partialState ()
140
+ {
141
+ return self ::_partialState ();
142
+ }
143
+
144
+ /**
145
+ * @return ObjectMergeState
146
+ */
147
+ private static function _partialState ()
148
+ {
149
+ $ state = new ObjectMergeState ();
150
+
151
+ $ state ->recursive = self ::$ _recursive ;
152
+ $ state ->opts = self ::$ _opts ;
153
+ $ state ->depth = self ::$ _depth ;
154
+ $ state ->context = self ::$ _context ;
155
+
156
+ return $ state ;
157
+ }
158
+
159
+ /**
160
+ * @param string|int $key
161
+ * @param mixed $leftValue
162
+ * @param mixed $rightValue
163
+ * @return ObjectMergeState
164
+ */
165
+ private static function _fullState ($ key , $ leftValue , $ rightValue )
166
+ {
167
+ $ state = self ::_partialState ();
168
+
169
+ $ state ->key = $ key ;
170
+ $ state ->leftValue = $ leftValue ;
171
+ $ state ->rightValue = $ rightValue ;
172
+
173
+ return $ state ;
110
174
}
111
175
112
176
private static function _down ()
@@ -127,9 +191,9 @@ private static function _up()
127
191
private static function _exceptionMessage ($ prefix )
128
192
{
129
193
return sprintf (
130
- '%s - $recurse =%s; $opts=%d; $depth=%d; $context=%s ' ,
194
+ '%s - $recursive =%s; $opts=%d; $depth=%d; $context=%s ' ,
131
195
$ prefix ,
132
- self ::$ _recurse ,
196
+ self ::$ _recursive ,
133
197
self ::$ _opts ,
134
198
self ::$ _depth ,
135
199
implode ('-> ' , self ::$ _context )
@@ -270,6 +334,23 @@ private static function _mergeValues($key, $leftValue, $rightValue)
270
334
{
271
335
self ::$ _context [self ::$ _depth ] = $ key ;
272
336
337
+ if (isset (self ::$ _cb )) {
338
+ $ res = call_user_func (self ::$ _cb , self ::_fullState ($ key , $ leftValue , $ rightValue ));
339
+ $ resT = gettype ($ res );
340
+ if (self ::OBJECT_T === $ resT ) {
341
+ if ($ res instanceof ObjectMergeResult && !$ res ->shouldContinue ()) {
342
+ $ finalValue = $ res ->getFinalValue ();
343
+ if (OBJECT_MERGE_UNDEFINED !== $ finalValue ) {
344
+ return $ finalValue ;
345
+ }
346
+ $ leftValue = $ res ->getLeftValue ();
347
+ $ rightValue = $ res ->getRightValue ();
348
+ }
349
+ } else {
350
+ return $ res ;
351
+ }
352
+ }
353
+
273
354
$ leftUndefined = object_merge_value_undefined ($ leftValue , self ::$ _opts );
274
355
$ rightUndefined = object_merge_value_undefined ($ rightValue , self ::$ _opts );
275
356
@@ -310,7 +391,7 @@ private static function _mergeValues($key, $leftValue, $rightValue)
310
391
return self ::_mergeValues ($ key , self ::_newEmptyValue ($ rightValue ), $ rightValue );
311
392
}
312
393
313
- if (!self ::$ _recurse || in_array ($ leftType , self ::$ _SIMPLE_TYPES , true )) {
394
+ if (!self ::$ _recursive || in_array ($ leftType , self ::$ _SIMPLE_TYPES , true )) {
314
395
return $ rightValue ;
315
396
}
316
397
@@ -322,12 +403,13 @@ private static function _mergeValues($key, $leftValue, $rightValue)
322
403
}
323
404
324
405
/**
325
- * @param bool $recurse
406
+ * @param bool $recursive
326
407
* @param int $opts
408
+ * @param callable|null $cb
327
409
* @param array $objects
328
410
* @return mixed|null
329
411
*/
330
- private static function _doMerge ($ recurse , $ opts , array $ objects )
412
+ private static function _doMerge ($ recursive , $ opts, $ cb , array $ objects )
331
413
{
332
414
if ([] === $ objects ) {
333
415
return null ;
@@ -336,8 +418,9 @@ private static function _doMerge($recurse, $opts, array $objects)
336
418
$ root = null ;
337
419
338
420
// set state
339
- self ::$ _recurse = $ recurse ;
421
+ self ::$ _recursive = $ recursive ;
340
422
self ::$ _opts = $ opts ;
423
+ self ::$ _cb = $ cb ;
341
424
342
425
foreach ($ objects as $ object ) {
343
426
if (null === $ object ) {
@@ -349,14 +432,15 @@ private static function _doMerge($recurse, $opts, array $objects)
349
432
continue ;
350
433
}
351
434
352
- $ root = self ::_mergeObjectValues ($ root , !$ recurse ? clone $ object : $ object );
435
+ $ root = self ::_mergeObjectValues ($ root , !$ recursive ? clone $ object : $ object );
353
436
}
354
437
355
438
// reset state
356
439
self ::$ _depth = -1 ;
357
440
self ::$ _context = [];
358
- self ::$ _recurse = false ;
441
+ self ::$ _recursive = false ;
359
442
self ::$ _opts = 0 ;
443
+ self ::$ _cb = null ;
360
444
361
445
return $ root ;
362
446
}
0 commit comments