這三個都是 Laravel 所提供的 helpers 函式。剛好今天聽到有人提到這個問題,所以就來翻看看。
單就註解與介面來看這三個函式:
function array_get($array, $key, $default = null);
function data_get($target, $key, $default = null);
function object_get($object, $key, $default = null);
|
可以約略知道 array_get()
與 object_get()
分別在處理 array 與 object,而 data_get()
則是混合的。
array_get()
接著來看 array_get()
原始碼:
function array_get($array, $key, $default = null) { return Arr::get($array, $key, $default); }
|
它是把任務交付給 Arr 類別處理的
會這樣做有兩種可能:一種是因為 4.1 版以前,並沒有 Arr 類別,這是為了符合過去的習慣所留下來的,但這個可能性較小。較有可能是因為 array 處理越來越複雜,為了讓檔案可以 SRP,所以就另外寫了一個靜態類別來處理。
public static function get($array, $key, $default = null) { if (! static::accessible($array)) { return value($default); }
if (is_null($key)) { return $array; }
if (static::exists($array, $key)) { return $array[$key]; }
if (strpos($key, '.') === false) { return $array[$key] ?? value($default); }
foreach (explode('.', $key) as $segment) { if (static::accessible($array) && static::exists($array, $segment)) { $array = $array[$segment]; } else { return value($default); } }
return $array; }
public static function accessible($value) { return is_array($value) || $value instanceof ArrayAccess; }
public static function exists($array, $key) { if ($array instanceof ArrayAccess) { return $array->offsetExists($key); }
return array_key_exists($key, $array); }
|
這裡面不意外的,都是使用 array 的方法在取內容。
object_get()
類似地,object_get()
則是對 object 型態的變數取資料:
function object_get($object, $key, $default = null) { if (is_null($key) || trim($key) == '') { return $object; }
foreach (explode('.', $key) as $segment) { if (! is_object($object) || ! isset($object->{$segment})) { return value($default); }
$object = $object->{$segment}; }
return $object; }
|
整個過程都是使用 object 的取屬性方法(->
)。
data_get()
array_get()
必須要所有階層都是 array 或 ArrayAccess 實例,才能正常地使用。object_get()
則要每一階層都是 object。
如果是 array 包 object 或相反,就需要靠 data_get()
了。因為它除了同時支援兩種取資料方法,還另外實作了 *
的取資料方法,所以原始碼也比較複雜的:
function data_get($target, $key, $default = null) { if (is_null($key)) { return $target; }
$key = is_array($key) ? $key : explode('.', $key);
while (! is_null($segment = array_shift($key))) { if ($segment === '*') { if ($target instanceof Collection) { $target = $target->all(); } elseif (! is_array($target)) { return value($default); }
$result = Arr::pluck($target, $key);
return in_array('*', $key) ? Arr::collapse($result) : $result; }
if (Arr::accessible($target) && Arr::exists($target, $segment)) { $target = $target[$segment]; } elseif (is_object($target) && isset($target->{$segment})) { $target = $target->{$segment}; } else { 都不是的話,key 是有問題的,只好回傳預設值 return value($default); } }
return $target; }
|
*
的用法,比方說在分析 Routing(5)曾提到 addToCollections()
會建立查詢表:
$domainAndUri = $route->getDomain().$route->uri();
foreach ($route->methods() as $method) { $this->routes[$method][$domainAndUri] = $route; }
|
下面是應用方法:
data_get($this->routes, 'get.*');
data_get($this->routes, '*./user');
|
三種方法都可以像 Javascript 使用 .
來取得多維陣列或 object 的取,像 config()
在取設定的時候,正是使用這些方法。
平常如果要對一堆資料操作的話,還是都會選擇使用 Collection,未來有機會再來翻翻它的原始碼。