PHPのサブジェクト指向設計

記事は痛みについて言うことができます。

エントリーのしきい値が低いこと、MySQLとの接続の習慣、アセンブリの必要性の欠如、厳密な型指定などの要素がないため、PHPで書かれたプロジェクトは、品質が高くなく、美しくきれいなコードではなく、データベースへの多くのクエリが含まれていることがよくあります。



PHPはスクリプト言語であり、サーバーはリクエストに応答し、オブジェクトは消滅します。 はい、これはデスクトップアプリケーションではありません。

ただし、これは、作業を行う必要があるサブジェクトエリアのオブジェクトがまったく必要ないという意味ではありません。

それどころか! それらは必要であり、メモリから削除された後、状態を維持および復元するのに役立ちます。



PHPで高品質のコードを書くことができますし、そうすべきです。他の点では、言語にまったく依存しません。

まず第一に、この記事は初心者にとっては有用ですが、経験豊富な開発者にとっても害はないと思います。 おそらく、あなたのプロジェクトでは、すべてが私たちが望むようなものではありませんか?



私はもう3年PHPを開発していますが、一つのことが常に苦しめられています。 コード内のエンティティを操作する代わりに、データベースを操作します。 これはルートでは真実ではありませんが。

高品質の製品はたくさんあると思いますが、ほとんどの場合、状況は非常に悲しいです。



作業する必要があるすべてのプロジェクトで、コードには、作業が必要なサブジェクト領域のモデルと、従う必要のあるカプセル化が明確に定義されていません。 どこでも同じです



低品質のプロジェクトでは、「モデル」の概念が完全に欠落していることがよくあります。データベースから何かを引き出したコードには複雑なロジックがあり、その後、膨大な数のサイクルと条件があり、その後データがテンプレートに入ります。 さらに、多くの場合、MySQLクエリが未使用のアプリケーションは、PDOを介したラッパーを使用した場合でも有効です。



高品質のプロジェクトはORMを使用しますが、これは特定の機能を実装するために協力したいものではありません。 とにかく、何かをするには、データベースを接続した状態で、「モデル」を調べたり、接続を確認したり、コンソールでDESC / EXPLAINを実行したりする必要があります。

その結果、アプリケーションコードはエンティティメソッドのデータに対する操作を隠しません。 そして、単純な(またはそうではない)ビジネスロジックがあるはずのコードには、Orm :: findのような行がたくさんあります。

このようなミッシュマッシュは非常に苦痛です。 特に、プロジェクトが大きく、書き換えが不可能な場合。 最大は、新しいコードを並行して保持し、それを使用し、時間の経過とともに古いコードから徐々に離れることです。



Eric Evansの注目すべき本「Object-Oriented Design」(記事の最後のリンク)、またはDomain-Driven Designを読んだ後、ほとんどのPHP開発はデータベースから行をプルすることになりました。



正しい方法では、オブジェクトとその集合体がプロジェクト内に存在している必要があり、そのインターフェイスを介してサブジェクト領域のエンティティを操作できます。

ユニット内を移動してその従属オブジェクトに登る必要はありません。同様に、オブジェクトを操作する代わりに「クエリを書き込む」べきではありません。



オブジェクトは、データベースから回復するだけでなく、 状態を維持できる必要があります。 複雑なオブジェクトとアセンブリの場合、ファクトリを使用できます。 しかし、すべてのロジックをmysqlクエリに基づいてはいけません。



ただし、悪意を持って作業する必要があったすべてのプロジェクトは、このアーキテクチャの規則に違反しています。



非常に簡単な例を示します。



顧客-顧客エンティティエンティティ

注文-集合オブジェクト「注文」

注文の単位は、不変の値オブジェクト「OrderItem」です



顧客は多数の注文を行うことができ、1つの注文は多数のユニットで構成できます。

注文単位は変更されていない値です。 商品の価格の変更(および顧客での割引)の場合、または商品がストアから削除される場合、注文履歴は信頼性が高く、購入時に関連していたデータを保存する必要があります。 単に商品を指すのは間違っています。



そのため、ユーザーの注文を表示するAPIメソッド/コントローラーで簡単なロジックを記述する必要があります。

コードは意図的に簡略化されており、本質のみを示しています。 この場合、IDがどのように入力され、ユーザーをどのように認証するかは重要ではありません。



オプション1:



 $ order = Orm :: find( 'Order'、[['id'、$ id]、['user_id'、$ user-> getId()]]);
 if(!empty($ order)){
   $ items = Orm :: find( 'OrderItem'、[['order_id'、$ id]]); 
   $アイテムを返します。
 } else {
   return '注文が見つかりませんでした';
 }




オプション2:



 $ order = $ user-> getOrder($ id);
 return $ order-> getItems();




最初のケースでは、他の誰かの注文を発行しないように、データベースにアクセスして現在のユーザーからリクエストされたIDで注文を取得します。

次に、データベースにアクセスして、OrderItemテーブルからこの注文に関連付けられているレコードを取得します。

次に、ほとんどの場合、foreach / array_walk / array_mapを使用して結果を「ソート」して、データを目的の形式にする必要があります。



このようなコードは間違いなく機能しますが、すぐに同じものになり、プロジェクトのさまざまな部分で複製されます。

このような課題は、プロジェクトの構築されたアーキテクチャを完全に台無しにし、単に無意味にします。



コードの最初のバージョンを維持することははるかに難しく、2番目のバージョンほど読みやすいものではありません。 Orm ::このような明らかなパラメーターと追加条件を常に持つとは限らないcを見つけます。



データベース内の注文の保存が変更された場合、せいぜいコード全体でORM呼び出しを検索および編集する必要があります。



2番目のケースでは、便利なインターフェイスを備えたエンティティを発音しました。

getOrderメソッドには、注文とユーザーの通信を確認するためのロジックが既に組み込まれています。この場合、たとえば、例外がスローされます。 また、 getItemsメソッドには、位置のリストを単純に返すために必要なすべてのものがすでに含まれています。 このコードを読むと、実際に何をするのかがすぐにわかります。 さらに、このようなコードはテストが簡単です。 すべてを1行で書くこともできます。



  return $ user-> getOrder($ id)-> getItems(); 




結論:



別のプログラマが開発中に書き始めた彼のプロジェクトの1つで、データベースでの作業をカプセル化するだけでなく、そのアーキテクチャの欠陥と暗黙のフィールド名を隠すモデルを導入します。



将来的に作業を楽しみ、簡単に保守できるようにコードを記述してください。

OOPを使用してコードを記述しているので、オブジェクトを操作して、このパラダイムを最大限に活用しましょう。

プロジェクトで説明するビジネスロジックは、mysqlの選択と配列ではなく、エンティティに基づいています。 自分や他の人の生活を複雑にしないでください!



本質を説明するクラスを書くのを怠らないでください。必要に応じて、あなたにとって有用なメソッドを書くのを怠らないでください。コピー&ペーストは悪です。 そして、既製のエンティティと既製のメソッドのセットにより、その後の開発、リファクタリング、テストが簡素化され、加速されます!



PS:この記事は単なる参考になります。



ブックリンク: エリックエヴァンス-主題指向デザイン



All Articles