PHP Conference Japan 2024

ArrayObject 類別

(PHP 5, PHP 7, PHP 8)

簡介

此類別允許物件以陣列的方式運作。

注意 以此類別包裝物件基本上存在缺陷,因此不建議將其與物件一起使用。

類別概要

class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Countable {
/* 常數 */
public const int STD_PROP_LIST;
public const int ARRAY_AS_PROPS;
/* 方法 */
public __construct(array|object $array = [], int $flags = 0, string $iteratorClass = ArrayIterator::class)
public append(mixed $value): void
public asort(int $flags = SORT_REGULAR): true
public count(): int
public getFlags(): int
public ksort(int $flags = SORT_REGULAR): true
public natcasesort(): true
public natsort(): true
public offsetExists(mixed $key): bool
public offsetGet(mixed $key): mixed
public offsetSet(mixed $key, mixed $value): void
public offsetUnset(mixed $key): void
public serialize(): string
public setFlags(int $flags): void
public setIteratorClass(string $iteratorClass): void
public uasort(callable $callback): true
public uksort(callable $callback): true
public unserialize(string $data): void
}

預定義常數

ArrayObject 旗標

ArrayObject::STD_PROP_LIST

當以清單存取(var_dump()foreach 等)時,物件的屬性具有其正常功能。

ArrayObject::ARRAY_AS_PROPS

條目可以作為屬性存取(讀取和寫入)。ArrayObject 類別使用其自己的邏輯來存取屬性,因此嘗試讀取或寫入動態屬性時不會引發警告或錯誤。

目錄

新增筆記

使用者貢獻筆記 10 則筆記

php5 dot man at lightning dot hu
12 年前
如您所知,ArrayObject 不是陣列,所以您無法使用內建的陣列函式。這裡有一個解決方法

使用您自己的類別擴展 ArrayObject 類別,並實作這個魔術方法

<?php
public function __call($func, $argv)
{
if (!
is_callable($func) || substr($func, 0, 6) !== 'array_')
{
throw new
BadMethodCallException(__CLASS__.'->'.$func);
}
return
call_user_func_array($func, array_merge(array($this->getArrayCopy()), $argv));
}
?>

現在您可以對任何 array_* 函式執行此操作
<?php
$yourObject
->array_keys();
?>
- 別忘了省略第一個參數 - 它是自動的!

注意:如果您正在處理大量資料,您可能需要編寫自己的函式。
rwn dot gallego at gmail dot com
11 年前
這裡有關於 ArrayObject 旗標 (STD_PROP_LIST 和 ARRAY_AS_PROPS) 的更好解釋

http://stackoverflow.com/a/16619183/1019305

感謝 JayTaph
bub at gmail dot com
2 年前
如果您需要集合的最後一個鍵,請使用
<?php
array_key_last
($this->getArrayCopy())
?>

在擴展類別中,它可能看起來像
<?php
class Collection extends ArrayObject
{
public function
lastKey(): int
{
return
array_key_last($this->getArrayCopy());
}
}
?>

如果您想使用任何型別安全的集合
<?php
class BookCollection extends Collection
{
public function
add(Book $book) : void
{
$this->offsetSet($book->id, $book);
}

// 請注意回傳型別 "Book"
public function get(int $bookId) : Book
{
$this->offsetGet($bookId);
}
}
?>
MarkAndrewSlade at gmail dot com
13 年前
我發現 STD_PROP_LIST 的描述有點模糊,所以我整理了一個簡單的示範來展示它的行為

<?php

$a
= new ArrayObject(array(), ArrayObject::STD_PROP_LIST);
$a['arr'] = '陣列資料';
$a->prop = '屬性資料';
$b = new ArrayObject();
$b['arr'] = '陣列資料';
$b->prop = '屬性資料';

// ArrayObject 物件
// (
// [prop] => 屬性資料
// )
print_r($a);

// ArrayObject 物件
// (
// [arr] => 陣列資料
// )
print_r($b);

?>
deminy at deminy dot net
15 年前
通常變數 $this 不能在物件上下文中用作陣列。例如,以下程式碼片段會導致嚴重錯誤

<?php
class TestThis {
public function
__set($name, $val) {
$this[$name] = $val;
}

public function
__get($name) {
return
$this[$name];
}
}

$obj = new TestThis();
$obj->a = 'aaa';
echo
$obj->a . "\n";
?>

但是當 $this 在 ArrayObject 物件中使用時,情況會有所不同。例如,以下程式碼片段是有效的

<?php
class TestArrayObject extends ArrayObject {
public function
__set($name, $val) {
$this[$name] = $val;
}

public function
__get($name) {
return
$this[$name];
}
}

$obj = new TestArrayObject();
$obj->a = 'aaa';
echo
$obj->a . "\n";
?>
Gilles A
10 年前
// STD_PROP_LIST 和 ARRAY_AS_PROP 結合的範例
<?php
$ao
= new ArrayObject();
$ao ->setFlags(ArrayObject::STD_PROP_LIST|ArrayObject::ARRAY_AS_PROPS);

$ao->prop = '屬性資料';
$ao['arr'] = '陣列資料';

print_r($ao);

?>

// 結果

ArrayObject 物件
(
[storage:ArrayObject:private] =&gt; 陣列
(
[prop] => 屬性資料
[arr] => 陣列資料
)

)
hello at rayfung dot hk
3 年前
如果您想將內建的陣列函式與 ArrayObject 一起使用,請儲存迭代器實例,並在 offsetGet 中將值作為參考回傳。

<?php
class Collection extends \ArrayObject {
public function
__construct(array $data = [])
{
if (!
\is_array($data) && !\array_key_exists('ArrayAccess', class_implements($data))) {
$data = [$data];
}

$this->iterator = $this->getIterator();
parent::__construct($data);
}

public function &
offsetGet($index)
{
$value = &$this->iterator[$index] ?? null;

return
$value;
}
}
?>
Vuong Nguyen
6 年前
您可以輕鬆地發現 ArrayObject 可以像在 ArrayIterator 中一樣使用各種函式來迭代一個物件作為陣列。但是,您需要先使用 getIterator() 來「啟用」這些函式(rewind、valid、next 等...)。實際上,這個函式繼承自 Iterator Aggregate 介面。

請看以下基本範例。結果相同

<?php

$array
= [1, 2, 3, 4];
$a = new ArrayObject($array);
$b = new ArrayIterator($array);

$iterator = $a->getIterator();

for(
$iterator->rewind(); $iterator->valid(); $iterator->next()){
echo
$iterator->current()*2;

}

for(
$b->rewind(); $b->valid(); $b->next()){
echo
$b->current()*2;

}

//結果相同 2468 以及 2468
sfinktah at php dot spamtrak dot org
13 年前
如果您計劃從 ArrayObject 衍生自己的類別,並希望維持完整的 ArrayObject 功能(例如能夠轉換為陣列),則必須使用 ArrayObject 自己的私有屬性 "storage"。

由於無法直接執行此操作,您必須使用 ArrayObject 的 offset{Set,Get,Exists,Unset} 方法間接操作它。

另一個好處是,這表示您繼承了所有迭代和其他功能,並能完整運作。

對於從未實作自己的 ArrayObject 類別的人來說,這可能聽起來很明顯...但事實遠非如此。

<?php

class MyArrayObject extends ArrayObject {
static
$debugLevel = 2;

static public function
sdprintf() {
if (static::
$debugLevel > 1) {
call_user_func_array("printf", func_get_args());
}
}

public function
offsetGet($name) {
self::sdprintf("%s(%s)\n", __FUNCTION__, implode(",", func_get_args()));
return
call_user_func_array(array(parent, __FUNCTION__), func_get_args());
}
public function
offsetSet($name, $value) {
self::sdprintf("%s(%s)\n", __FUNCTION__, implode(",", func_get_args()));
return
call_user_func_array(array(parent, __FUNCTION__), func_get_args());
}
public function
offsetExists($name) {
self::sdprintf("%s(%s)\n", __FUNCTION__, implode(",", func_get_args()));
return
call_user_func_array(array(parent, __FUNCTION__), func_get_args());
}
public function
offsetUnset($name) {
self::sdprintf("%s(%s)\n", __FUNCTION__, implode(",", func_get_args()));
return
call_user_func_array(array(parent, __FUNCTION__), func_get_args());
}
}

$mao = new MyArrayObject();
$mao["name"] = "bob";
$mao["friend"] = "jane";
print_r((array)$mao);

/* 輸出:

offsetSet(name,bob)
offsetSet(friend,jane)
Array
(
[name] => bob
[friend] => jane
) */
?>

如果您希望使用「陣列如同屬性」旗標,您只需在建構子中加入此行

<?php parent::setFlags(parent::ARRAY_AS_PROPS); ?>

這將允許您執行以下範例之類的操作,而無需覆寫 __get 或 __set。

<?php
$mao
->name = "Phil";
echo
$mao["name"]; /* 輸出 "Phil" */
?>
rudie
6 年前
如果您希望數值 ArrayObject 物件能與 json_encode() 正常運作,請實作 JsonSerializable

class JsonSerializableArrayObject extends ArrayObject implements JsonSerializable {
function jsonSerialize() {
return $this->getArrayCopy();
}
}

對於關聯式 ArrayObject 物件,這並非必要,但對於數值陣列來說是必要的,否則它們會格式化成

{"0":"jaap","1":"karel"}

而不是

["jaap","karel"]
To Top