Merges an incoming value into the current one, recursing by value shape.
Description
This is the core of the merge algorithm and is applied at every nesting level: a scalar (or null) in $incoming replaces $current outright, an associative array merges key by key (recursing here for each key, with a null value deleting that key), and a list either replaces $current wholesale ($replace_lists) or merges into it by member identity. The $replace_lists flag is carried down through associative nesting so that, under replace(), every list reached along the way is swapped wholesale.
An array in $incoming only merges into a current value of the same shape.
A non-empty mismatch — an associative array where a list lives, or a non-empty list where an associative value lives — is reported with _doing_it_wrong() and leaves the current value unchanged, so a malformed patch cannot silently destroy configuration. An empty array is shape-ambiguous and merges nothing, so it is a no-op: clearing a list is spelled replace() with an empty list, and resetting a key is spelled null.
Parameters
$currentmixedrequired- The current value.
$incomingmixedrequired- The incoming value.
$replace_listsboolrequired- Whether a list in $incoming replaces the current list wholesale instead of merging into it by member identity.
Source
private function merge_properties( $current, $incoming, $replace_lists ) {
// Scalar properties are merged as-is.
if ( ! is_array( $incoming ) ) {
return $incoming;
}
// Numerical indexed arrays are expected to be lists (sequential integer keys starting at 0).
if ( array_is_list( $incoming ) ) {
// A non-empty list only lands where a list (or nothing) lives, under
// merge() and replace() alike. An empty array is shape-ambiguous and
// exempt, so replace() with an empty list can still clear a list.
if ( array() !== $incoming && is_array( $current ) && ! array_is_list( $current ) && array() !== $current ) {
_doing_it_wrong(
__METHOD__,
esc_html__( 'A view configuration patch value must match the shape of the value it patches: a list merges into a list, and an associative array into an associative array.' ),
'7.1.0'
);
return $current;
}
// replace() takes an incoming list as-is; merge() merges it by member identity.
if ( $replace_lists ) {
// As-is except for nulls: a list swapped in wholesale has no
// existing leaf for a null to delete (the same rationale as
// set()), so a null member is dropped rather than stored.
return $this->strip_nulls( $incoming );
}
// An empty list has no members to merge, and an empty array is
// shape-ambiguous, so merging one is a no-op rather than a reset.
if ( array() === $incoming ) {
return $current;
}
return $this->merge_list_by_identity(
is_array( $current ) && array_is_list( $current ) ? $current : array(),
$incoming
);
}
// Consider any other array as associative (keys are strings).
if ( is_array( $current ) && array_is_list( $current ) && array() !== $current ) {
_doing_it_wrong(
__METHOD__,
esc_html__( 'A view configuration patch value must match the shape of the value it patches: a list merges into a list, and an associative array into an associative array.' ),
'7.1.0'
);
return $current;
}
$result = is_array( $current ) && ! array_is_list( $current ) ? $current : array();
foreach ( $incoming as $key => $value ) {
// A null patch value deletes the property.
if ( null === $value ) {
unset( $result[ $key ] );
continue;
}
$result[ $key ] = $this->merge_properties(
array_key_exists( $key, $result ) ? $result[ $key ] : array(),
$value,
$replace_lists
);
}
return $result;
}
Changelog
| Version | Description |
|---|---|
| 7.1.0 | Introduced. |
User Contributed Notes
You must log in before being able to contribute a note or feedback.