目次
配列をリストとして使用する" >配列をリストとして使用する
すべての要素は同じ型である必要があります" >すべての要素は同じ型である必要があります
各要素のインデックスは無視してください。" >各要素のインデックスは無視してください。
要素を削除する代わりにフィルターを使用する " >要素を削除する代わりにフィルターを使用する
すべてのキーは同じ型である必要があります" >すべてのキーは同じ型である必要があります
すべての値は同じ型でなければなりません " >すべての値は同じ型でなければなりません
マップはプライベートに保つ必要があります。 " >マップはプライベートに保つ必要があります。
複数の値タイプのマッピングにはオブジェクトを使用する" >複数の値タイプのマッピングにはオブジェクトを使用する
これらの規則の例外" >これらの規則の例外
自定义集合类" >自定义集合类
使用自定义集合类来防止重复逻辑" >使用自定义集合类来防止重复逻辑
使用自定义集合类来解耦客户端" >使用自定义集合类来解耦客户端
自定义集合类的一些规则" >自定义集合类的一些规则
让它们不可变" >让它们不可变
只提供实际客户需要和使用的行为" >只提供实际客户需要和使用的行为
使用 IteratorAggregate 和 ArrayIterator 来支持迭代" >使用 IteratorAggregate 和 ArrayIterator 来支持迭代
权衡考虑" >权衡考虑
ホームページ バックエンド開発 PHPチュートリアル PHP の配列仕様とカスタム コレクション

PHP の配列仕様とカスタム コレクション

Jun 17, 2020 pm 05:41 PM
php

PHP の配列仕様とカスタム コレクション

これはほぼ 配列設計 のスタイル ガイドですが、これを オブジェクト デザイン スタイル ガイド に追加するのは違和感があります。そう、すべてのオブジェクト指向言語が動的配列を持っているわけではないからです。 PHP は Java (よく知られているかもしれません) によく似ているため、この記事の例は PHP で書かれていますが、組み込みのコレクション クラスやインターフェイスの代わりに動的配列を使用します。

配列をリストとして使用する

すべての要素は同じ型である必要があります

リストとしての配列 リスト (特定の順序での値のコレクション) の場合、各値は z:

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

$badList = [
    'a',
    1
];
ログイン後にコピー

型である必要があります。リスト型に注釈を付けるための一般的に受け入れられているスタイルは次のとおりです:@var配列<TypeOfElement> 。インデックスのタイプを追加しないように注意してください (常に int です)。

各要素のインデックスは無視してください。

PHP は、リスト内の各要素 (0、1、2 など) に新しいインデックスを自動的に作成します。ただし、これらのインデックスに依存したり、直接使用したりしないでください。クライアントが依存する必要があるリストのプロパティは、iterablecountable だけです。

したがって、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 など) ではなく

に関連している場合、配列をマップとして使用します

。配列をマップとして自由に使用できます (マップから値を一意のキーで取得できます)。

すべてのキーは同じ型である必要があります

配列をマップとして使用する最初のルールは、配列内のすべてのキーが同じ型である必要があります (最も一般的なもの) 1 つはタイプ 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></typeofkey> です。

マップはプライベートに保つ必要があります。

リストはその単純な特性により、オブジェクト間で安全に受け渡すことができます。すべてのクライアントは、リストが空であっても、これを使用して要素をループしたり、要素をカウントしたりできます。クライアントは対応する値を持たないキーに依存する可能性があるため、マッピングの処理はさらに困難になります。これは、一般に、それらを管理するオブジェクトに対してプライベートにしておく必要があることを意味します。クライアントは内部マッピングに直接アクセスすることはできません。代わりに、値を取得するためにゲッター (場合によってはセッター) が提供されます。要求されたキーの値が存在しない場合、例外がスローされます。ただし、マップとその値を完全に非公開にできる場合は、そうしてください。

// 公开一个列表是可以的

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

// 公开地图可能很麻烦

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

// 相反,提供一种方法来根据其键检索值

/**
 * @throws UserNotFound
 */ 
public function userById(string $id): User
{ 
    // ...
}
ログイン後にコピー

複数の値タイプのマッピングにはオブジェクトを使用する

異なる タイプの 値を 1 つのマッピングに格納したい場合は、を使用してくださいオブジェクト。クラスを定義し、そのクラスに型指定されたパブリック プロパティを追加するか、コンストラクターとゲッターを追加します。このようなオブジェクトの例は、構成オブジェクトやコマンド オブジェクトです。

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

以上がPHP の配列仕様とカスタム コレクションの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Ubuntu および Debian 用の PHP 8.4 インストールおよびアップグレード ガイド Ubuntu および Debian 用の PHP 8.4 インストールおよびアップグレード ガイド Dec 24, 2024 pm 04:42 PM

PHP 8.4 では、いくつかの新機能、セキュリティの改善、パフォーマンスの改善が行われ、かなりの量の機能の非推奨と削除が行われています。 このガイドでは、Ubuntu、Debian、またはその派生版に PHP 8.4 をインストールする方法、または PHP 8.4 にアップグレードする方法について説明します。

今まで知らなかったことを後悔している 7 つの PHP 関数 今まで知らなかったことを後悔している 7 つの PHP 関数 Nov 13, 2024 am 09:42 AM

あなたが経験豊富な PHP 開発者であれば、すでにそこにいて、すでにそれを行っていると感じているかもしれません。あなたは、運用を達成するために、かなりの数のアプリケーションを開発し、数百万行のコードをデバッグし、大量のスクリプトを微調整してきました。

PHP 開発用に Visual Studio Code (VS Code) をセットアップする方法 PHP 開発用に Visual Studio Code (VS Code) をセットアップする方法 Dec 20, 2024 am 11:31 AM

Visual Studio Code (VS Code とも呼ばれる) は、すべての主要なオペレーティング システムで利用できる無料のソース コード エディター (統合開発環境 (IDE)) です。 多くのプログラミング言語の拡張機能の大規模なコレクションを備えた VS Code は、

JSON Web Tokens(JWT)とPHP APIでのユースケースを説明してください。 JSON Web Tokens(JWT)とPHP APIでのユースケースを説明してください。 Apr 05, 2025 am 12:04 AM

JWTは、JSONに基づくオープン標準であり、主にアイデンティティ認証と情報交換のために、当事者間で情報を安全に送信するために使用されます。 1。JWTは、ヘッダー、ペイロード、署名の3つの部分で構成されています。 2。JWTの実用的な原則には、JWTの生成、JWTの検証、ペイロードの解析という3つのステップが含まれます。 3. PHPでの認証にJWTを使用する場合、JWTを生成および検証でき、ユーザーの役割と許可情報を高度な使用に含めることができます。 4.一般的なエラーには、署名検証障害、トークンの有効期限、およびペイロードが大きくなります。デバッグスキルには、デバッグツールの使用とロギングが含まれます。 5.パフォーマンスの最適化とベストプラクティスには、適切な署名アルゴリズムの使用、有効期間を合理的に設定することが含まれます。

PHPでHTML/XMLを解析および処理するにはどうすればよいですか? PHPでHTML/XMLを解析および処理するにはどうすればよいですか? Feb 07, 2025 am 11:57 AM

このチュートリアルでは、PHPを使用してXMLドキュメントを効率的に処理する方法を示しています。 XML(拡張可能なマークアップ言語)は、人間の読みやすさとマシン解析の両方に合わせて設計された多用途のテキストベースのマークアップ言語です。一般的にデータストレージに使用されます

母音を文字列にカウントするPHPプログラム 母音を文字列にカウントするPHPプログラム Feb 07, 2025 pm 12:12 PM

文字列は、文字、数字、シンボルを含む一連の文字です。このチュートリアルでは、さまざまな方法を使用してPHPの特定の文字列内の母音の数を計算する方法を学びます。英語の母音は、a、e、i、o、u、そしてそれらは大文字または小文字である可能性があります。 母音とは何ですか? 母音は、特定の発音を表すアルファベットのある文字です。大文字と小文字など、英語には5つの母音があります。 a、e、i、o、u 例1 入力:string = "tutorialspoint" 出力:6 説明する 文字列「TutorialSpoint」の母音は、u、o、i、a、o、iです。合計で6元があります

PHPでの後期静的結合を説明します(静的::)。 PHPでの後期静的結合を説明します(静的::)。 Apr 03, 2025 am 12:04 AM

静的結合(静的::) PHPで後期静的結合(LSB)を実装し、クラスを定義するのではなく、静的コンテキストで呼び出しクラスを参照できるようにします。 1)解析プロセスは実行時に実行されます。2)継承関係のコールクラスを検索します。3)パフォーマンスオーバーヘッドをもたらす可能性があります。

PHPマジックメソッド(__construct、__destruct、__call、__get、__setなど)とは何ですか? PHPマジックメソッド(__construct、__destruct、__call、__get、__setなど)とは何ですか? Apr 03, 2025 am 12:03 AM

PHPの魔法の方法は何ですか? PHPの魔法の方法には次のものが含まれます。1。\ _ \ _コンストラクト、オブジェクトの初期化に使用されます。 2。\ _ \ _リソースのクリーンアップに使用される破壊。 3。\ _ \ _呼び出し、存在しないメソッド呼び出しを処理します。 4。\ _ \ _ get、dynamic属性アクセスを実装します。 5。\ _ \ _セット、動的属性設定を実装します。これらの方法は、特定の状況で自動的に呼び出され、コードの柔軟性と効率を向上させます。

See all articles