中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

數組在php中的應用

發布時間:2020-06-19 12:56:41 來源:億速云 閱讀:146 作者:鴿子 欄目:編程語言

這差不多是一個關于數組設計的風格指南,但是把它添加到對象設計風格指南感覺不太對,因為不是所有的面向對象語言都有動態數組。本文中的示例是用 PHP 編寫的,因為 PHP 很像 Java(可能比較熟悉),但是使用的是動態數組而不是內置的集合類和接口。

使用數組作為列表

所有元素都應該具有相同的類型

當使用一個數組作為一個列表(一個具有特定順序的值的集合)時,每個值應該是 z 類型:

$goodList = [
    'a',
    'b'
];

$badList = [
    'a',
    1
];

一個被普遍接受的注釋列表類型的風格是:@var array<TypeOfElement>。 確保不添加索引的類型(它總是int)。

應該忽略每個元素的索引

PHP 將自動為列表中的每個元素(0、1、2等)創建新索引。然而,你不應該依賴這些索引,也不應該直接使用它們。客戶端應該依賴的列表的唯一屬性是可迭代的可計數的

因此,可以隨意使用foreachcount(),但不要使用for循環遍歷列表中的元素:

// 好的循環:
foreach ($list as $element) {
}

// 不好的循環 (公開每個元素的索引):
foreach ($list as $index => $element) {
}

// 也是不好的循環 (不應該使用每個元素的索引):
for ($i = 0; $i < count($list); $i++) {
}

(在 PHP 中,for循環甚至可能不起作用,因為列表中可能缺少索引,而且索引可能比列表中的元素數量還要多。)

使用過濾器而不是刪除元素

你可能希望通過索引從列表中刪除元素(unset()),但是,你應該使用array_filter()來創建一個新列表(沒有不需要的元素),而不是刪除元素。

同樣,你不應該依賴于元素的索引,因此,在使用array_filter()時,不應該使用flag 參數去根據索引過濾元素,甚至根據元素和索引過濾元素。

// 好的過濾:
array_filter(
    $list, 
    function (string $element): bool { 
        return strlen($element) > 2; 
    }
);

// 不好的過濾器(也使用索引來過濾元素)
array_filter(
    $list, 
    function (int $index): bool { 
        return $index > 3;
    },
    ARRAY_FILTER_USE_KEY
);

// 不好的過濾器(同時使用索引和元素來過濾元素)
array_filter(
    $list, 
    function (string $element, int $index): bool { 
        return $index > 3 || $element === 'Include';
    },
    ARRAY_FILTER_USE_BOTH
);

使用數組作為映射

當鍵相關的,而不是索引(0,1,2,等等)。你可以隨意使用數組作為映射(可以通過其唯一的鍵從其中檢索值)。

所有的鍵應該是相同的類型

使用數組作為映射的第一個規則是,數組中的所有鍵都應該具有相同的類型(最常見的是string類型的鍵)。

$goodMap = [
    'foo' => 'bar',
    'bar' => 'baz'
];

// 不好(使用不同類型的鍵)
$badMap = [
    'foo' => 'bar',
    1 => 'baz'
];

所有的值都應該是相同的類型

映射中的值也是如此:它們應該具有相同的類型。

$goodMap = [
    'foo' => 'bar',
    'bar' => 'baz'
];

// 不好(使用不同類型的值)
$badMap = [
    'foo' => 'bar',
    'bar' => 1
];

一種普遍接受的映射類型注釋樣式是: @var array<TypeOfKey, TypeOfValue>

映射應該保持私有

列表可以安全地在對象之間傳遞,因為它們具有簡單的特征。任何客戶端都可以使用它來循環其元素,或計數其元素,即使列表是空的。映射則更難處理,因為客戶端可能依賴于沒有對應值的鍵。這意味著在一般情況下,它們應該對管理它們的對象保持私有。不允許客戶端直接訪問內部映射,而是提供 getter (可能還有 setter )來檢索值。如果請求的鍵不存在值,則拋出異常。但是,如果您可以保持映射及其值完全私有,那么就這樣做。

// 公開一個列表是可以的

/**
 * @return array<User>
 */
public function allUsers(): array
{
    // ...
}

// 公開地圖可能很麻煩

/**
 * @return array<string, User>
 */
public function usersById(): array
{ 
    // ...
}

// 相反,提供一種方法來根據其鍵檢索值

/**
 * @throws UserNotFound
 */ 
public function userById(string $id): User
{ 
    // ...
}

對具有多個值類型的映射使用對象

當你想要在一個映射中存儲不同類型的值時,請使用一個對象。定義一個類,并向其添加公共的類型化屬性,或添加構造函數和 getter。像這樣的對象的例子是配置對象,或者命令對象:

final class SillyRegisterUserCommand
{
    public string $username;
    public string $plainTextPassword;
    public bool $wantsToReceiveSpam;
    public int $answerToIAmNotARobotQuestion;
}

這些規則的例外

有時,庫或框架需要以更動態的方式使用數組。在這些情況下,不可能(也不希望)遵循前面的規則。例如數組數據,它將被存儲在一個數據庫表中,或者Symfony 表單配置。

自定義集合類

自定義集合類是一種非常酷的方法,最后可以和IteratorArrayAccess和其朋友一起使用,但是我發現大多數生成的代碼令人很困惑。第一次查看代碼的人必須在 PHP 手冊中查找詳細信息,即使他們是有經驗的開發人員。另外,你需要編寫更多的代碼,你必須維護這些代碼(測試、調試等)。所以在大多數情況下,我發現一個簡單的數組,加上一些適當的類型注釋,就足夠了。到底什么是需要將數組封裝到自定義集合對象中的強信號?

  • 如果你發現與那個數組相關的邏輯被復制了。
  • 如果你發現客戶端必須處理太多關于數組內部內容的細節。

使用自定義集合類來防止重復邏輯

如果使用相同數組的多個客戶端執行相同的任務(例如過濾、映射、減少、計數),則可以通過引入自定義集合類來消除重復。將重復的邏輯移到集合類的一個方法上,允許任何客戶端使用對集合的簡單方法調用來執行相同的任務:

$names = [/* ... */];

// 在幾個地方發現:
$shortNames = array_filter(
    $names, 
    function (string $element): bool { 
        return strlen($element) < 5; 
    }
);

// 變成一個自定義集合類:
use Assert\Assert;

final class Names
{
    /**
     * @var array<string>
     */
    private array $names;

    public function __construct(array $names)
    {
        Assert::that()->allIsString($names);
        $this->names = $names;
    }

    public function shortNames(): self
    {
        return new self(
            array_filter(
                $this->names, 
                function (string $element): bool { 
                    return strlen($element) < 5; 
                }
            )
        );
    }
}

$names = new Names([/* ... */]);
$shortNames = $names->shortNames();

在集合的轉換上使用方法的好處就是獲得了一個名稱。這使你能夠向看起來相當復雜的array_filter()調用添加一個簡短而有意義的標簽。

使用自定義集合類來解耦客戶端

如果一個客戶端使用特定的數組并循環,從選定的元素中取出一段數據,并對該數據進行處理,那么該客戶端就與所有涉及的類型緊密耦合: 數組本身、數組中元素的類型、它從所選元素中檢索的值的類型、選擇器方法的類型,等等。這種深度耦合的問題是,在不破壞依賴于它們的客戶端的情況下,很難更改所涉及類型的任何內容。因此,在這種情況下,你也可以將數組包裝在一個自定義 的集合類中,讓它一次性給出正確的答案,在內部進行必要的計算,讓客戶端與集合更加松散地耦合。

$lines = [];

$sum = 0;
foreach ($lines as $line) {
    if ($line->isComment()) {
        continue;
    }

    $sum += $line->quantity();
}

// Turned into a custom collection class:

final class Lines
{
    public function totalQuantity(): int
    {
        $sum = 0;

        foreach ($lines as $line) {
            if ($line->isComment()) {
                continue;
            }

            $sum += $line->quantity();
        }

        return $sum;
    }
}

自定義集合類的一些規則

讓我們看看在使用自定義集合類時應用的一些規則。

讓它們不可變

對集合實例的現有引用在運行某種轉換時不應受到影響。因此,任何執行轉換的方法都應該返回類的一個新實例,就像我們在上面的例子中看到的那樣:

final class Names
{
    /**
     * @var array<string>
     */
    private array $names;

    public function __construct(array $names)
    {
        Assert::that()->allIsString($names);
        $this->names = $names;
    }

    public function shortNames(): self
    {
        return new self(
            /* ... */
        );
    }
}

當然,如果要映射內部數組,則可能要映射到另一種類型的集合或簡單數組。與往常一樣,請確保提供適當的返回類型。

只提供實際客戶需要和使用的行為

你不必擴展泛型集合庫類,也不必自己在每個自定義集合類上實現泛型篩選器、映射和縮減方法,只實現真正需要的。如果某個方法在某一時刻不被使用,那么就刪除它。

使用 IteratorAggregate 和 ArrayIterator 來支持迭代

如果你使用 PHP,不用實現所有的Iterator接口的方法(并保持一個內部指針,等等),只是實現IteratorAggregate接口,讓它返回一個ArrayIterator實例基于內部數組:

final class Names implements IteratorAggregate
{
    /**
     * @var array<string>
     */
    private array $names;

    public function __construct(array $names)
    {
        Assert::that()->allIsString($names);
        $this->names = $names;
    }

    public function getIterator(): Iterator
    {
        return new ArrayIterator($this->names);
    }
}

$names = new Names([/* ... */]);

foreach ($names as $name) {
    // ...
}

以上就是PHP中數組規范和自定義集合的詳細內容,更多請關注億速云其它相關文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

阿克苏市| 仙居县| 交城县| 会东县| 嘉黎县| 遂平县| 黄浦区| 新和县| 贺州市| 莫力| 清远市| 汾阳市| 壤塘县| 武邑县| 眉山市| 溧阳市| 卫辉市| 江源县| 六枝特区| 咸阳市| 临猗县| 延吉市| 湾仔区| 阿合奇县| 徐水县| 玉龙| 普定县| 平定县| 治多县| 盐源县| 巢湖市| 西乌| 澄迈县| 缙云县| 孟连| 莱西市| 岢岚县| 盐亭县| 海林市| 怀集县| 大理市|