祖先のオーバーライド(ダーティハック)

UPD:もちろんこれを避ける方が良いです。 これはすべて恐ろしく、ひどく、臭いです。 しかし、それはVQMODより少し臭いが少なく、すでに「活気のある」更新された、しかし不気味なレガシーにパッチを適用する必要がある場合、このアプローチは存在する権利があります。 しかし、あなたが始めたばかりのプロジェクトでこれを決して行わないか、アーキテクチャをより拡張可能なものに変更することができます。 記事はそのままにします。 「記憶のために。」




コードを変更せずに親クラスの動作をオーバーライドしたい場合があります。
たとえば、テンプレートの保存場所をファイルからデータベースに変更するか、キャッシュを追加します。
または、ORMを置き換えて、レコードを削除済みとしてマークして削除します。
しかし、私たちが何を変えたいのか、あなたは決して知りません。
すべてのプログラマーがフレームワークの中核または他の誰かのコードに入ると、これは混乱になります。
このタスクには多くの解決策があります。 私が一番好きなものを提供したいです。
ソリューションは、 __ autoload()、またはspl_autoload_registerに基づいています。

このタスクのほとんどの実装には、「万が一に備えて」クラスに存在するかなりの量の特別なコードが含まれます(たとえば、フックを使用した拡張機能で行われます。これが必要です。
他のソリューションでは、システムのロジックを大幅に処理する必要があるため、理解が困難になることが多く、エントリのしきい値が高くなります。 (たとえば、イベントモデルのさまざまなバリエーション)。

私はすべてがシンプルであると同時に、可能な限り柔軟であることを望んでいます。
そして、そのような解決策が見つかりました:

一般に、アイデアはスリッパのように単純です:


すでに宣言されているクラスの動作を再定義できない場合、これらのクラスを宣言するプロセスを制御できます。 関数__autoload()は、クラスのロードを担当します。
したがって、振る舞いを変更したいクラスが__autoload()を介して呼び出された場合、 __autoload()の振る舞いを変更することにより、別のファイルから目的のクラスをロードできます。
実際、あるプロジェクトでは、フックの原理に基づいて__autoload()動作の再定義メカニズムを実装しました。
アプリケーションモジュールは、prbクラスをロードする関数を宣言し、メイン関数の前後で実行するために特定の方法で登録することができます。
ただし、この実装については説明しません。

これはすべて過去です!


最後に、ほとんどのホスティングサイトでphp 5.3が利用可能になり、古いブランチとの互換性を提供する必要がなくなりました。
ただし、5.3では、 SPLモジュールはカーネルの一部であり、デフォルトで使用可能です。
開発者は、このアイデアをspl_autoload_register関数の形式で既に実装していることがわかります。
spl_autoload_register関数は、単純にautoload関数同様の関数のスタックに記録します。
T.O. メイン関数をロードする前に変更されたクラスをロードする関数を記述すると、標準のコードではなくコードがロードされます。 一方、コード自動生成のオプションを追加する場合はメインコードの後に​​追加できます。

十分な理論


明らかに、すべての再定義可能なクラスは、直接ではなく自動ロードを介してロードする必要があります。

これはかなりダーティーなメソッドであり、そのようなソリューションはコードの読み取りとデバッグを非常に複雑にする可能性があるため、アプリケーションコードにそのような呼び出しを配置することは明確に推奨されません 。 そのようなフックはすべて、一目でわかりやすい場所にある必要があります 。 システムアーキテクトの場合、すべてのプログラマーが同様の機能を追加する場所とそれらを探す場所を知っていることを確認する必要があります。 また、システムがそのような機会を提供することを少なくとも認識している必要があります。

設計するとき、どのクラスをオーバーライドできるかを考えると便利です。
この考えから、いくつかのメソッドまたはプロパティを別のクラスに転送するよう促される場合があります。
個人的に、頻繁に交換されるクラスのために、2つのクラスを作成します-実装を持つクラスと、実装を持つクラスのみを継承するダミークラスです。 アプリケーションはダミーを使用します。 ダミーは簡単に再定義でき、何も変更しない標準機能を静かに継承できます。


すべての共通コードを含むcommon.phpファイル:
function start_module() { //      ....   common.php    index.php } function mainAutoload($class) { //    $filename = './class/'.$class.'.php'; if(file_exists()) require_once($filename); } 

デフォルトでは、index.phpには以下が含まれます。
 require_once 'common.php'; // //     spl_autoload_register('mainAutoload'); // //      start_module(); 


私たちのプロジェクトでは、 魂のクラスをオーバーライドしたい人がたくさんいると決めたとします
次に、soul.phpクラスを作成します。

 class soul extends soul_basic { //   . } 


それに応じて、soul_basic.php

 class soul_basic { public function good() { //       } public function evil() { //    } public function saintliness() { //    } public function business() { //    } } 


さて、「魂」を必要とする特定のオブジェクトは、 soul_basicからではなくsoulを実装または継承でき、 soul_basicに機能を実装できます。

ここで、すべての「魂」の振る舞いを変えたいと想像してください。
明らかに、プログラマーやディレクター、または魂から継承する他のクラスの「魂」のプロパティを再定義しても、私たちの助けにはなりません。 したがって、独自のソウルクラスを作成します。 これを行うには、index.phpファイルを次のように変更します。

 require_once 'common.php'; // //    . function century21Autoload($class) { if($class = 'soul') require_once('soul21.php'); } // //    spl_autoload_register('century21Autoload'); //     spl_autoload_register('mainAutoload'); // //      start_module(); 


それで、soul21.php:

 class soul extends soul_basic { public function good() { if(rand(0,100)>=80) parent::good(); else parent::evil(); } public function saintliness() { if($this->unit_name == 'Gundyaev') parent::bussiness(); else parent::saintliness(); } } 


PS:私は信者であり、教会を笑わないでください。 教会を信仰として、教会をビジネスとして分離するだけです。 そして、ビジネスで笑うことは罪だとは思いません。 私の友人や友人、異なる信仰の司祭は私に同意しませんが...

Source: https://habr.com/ru/post/J152499/


All Articles