ホームページ  >  記事  >  バックエンド開発  >  PHP オブジェクト指向、パターン、プラクティスの詳細

PHP オブジェクト指向、パターン、プラクティスの詳細

WBOY
WBOYオリジナル
2016-06-23 13:18:37979ブラウズ

PHP オブジェクト指向、パターン、実践の詳細

1 構文

1.1 基本構文

  1. clone

    元のオブジェクトを操作する必要があるが、元のオブジェクトに影響を与えたくない。

    $K_back = clone $K;

    両方とも基本データ型と配列はコピーに真であり、属性がオブジェクトの場合は偽のコピーになります。 解決策:

    //在原对象中添加function __clone(){    $this->对象 = clone $this->对象}

    __clone はクローン作成前に自動的にトリガーされます。バックアップ前にいくつかの属性操作を実行できます

  2. & 参照を渡す

    メソッド参照の転送、ソース オブジェクトを変更する

    function set_K(& $K){...}function & get_K(){...}
  3. 静的遅延静的バインディング

    アプリケーション シナリオ: Dog クラスと Person クラスの両方にインスタンス化を返すメソッドが必要です。 class と Person クラスは、Animal 抽象クラスを継承します。

    abstract class Animal{    public static function create(){        //实例化调用类        return new static();    }}class Person extends Animal{...}//返回Person实例化类Person::create();
  4. Interceptor
    1. __get($property)、未定義のプロパティにアクセスするときに呼び出されます。
    2. __set($property,$value)、未定義のプロパティに値を割り当てるときに呼び出されます。
    3. __isset($property)、未定義のプロパティで isset() メソッドが呼び出されたときに呼び出されます。
    4. __unset($property)、未定義のプロパティで unset() メソッドが呼び出されたときに呼び出されます。 ,$arg_array) は、未定義のメソッドが呼び出されたときに呼び出されます。
    5. __call は非常に便利ですが、柔軟性が高すぎるため、注意して使用する必要があります。
    6. //Person委托Person_Writer类处理打印事务.class Person {    private $writer;    ...    function __call($method_name,$args){        if(methood_exists($this->wirter,$method_name)){            return $this->writer->$method_name($this);        }    }    //高级__call写法,当委托方法参数不确定时使用.    function __call($method_name,$args){        //当然这里这样写法意义不大,但是call一般都是用call_user_func_array调用        $args = $this ;        if(methood_exists($this->wirter,$method_name)){            return call_user_func_array(                array($this->writer,$method_name),$args);            )        }    }}

      コールバック関数
    7. アプリケーションシナリオ: Product クラス、Product_Sale クラス、Product_Totalizer クラスの 3 つのクラスが実装されます: Product の販売総額が指定された金額を超えた場合。 、警告が出力されます。
    //Productclass Product {    public $name;    public $price;}//Product_Saleclass Product_Sale {    private $callbacks;    //记录回调函数    function register_callback ($callback) {        if(! is_callback($callback)){            thow new Exception('callback not callable');        }        $this->callbacks[] = $callback;    }    //执行回调函数    function sale ($product){        print "{$product->name} : 处理中 n";        foreach($this->callbacks as $callback){            call_user_func($callback , $product);        }    }}//Produce_Totalizerclass Produce_Totalizer {    static function warn_amount ($amt) {        $count = 0;        return function ($produce) use ($amt , &count) {            $count += $produce->price;            print " count : {count}n"            if($count>$amt){                print "超过指定金额{$amt}啦~";            }        };    }}//模拟场景$product_sale = new Produce_Sale();//指定报警金额为8块$product_sale = register_callback(Produce_Totalizer::warn_amount(8)); //卖商品$product_sale->sale(new Product("Durex",6));$product_sale->sale(new Produce("Jissbon",5));//输出结果Durex : 处理中    count :6 Jissbon : 处理中     count: 11超过指定金额8块啦~
  5. get_class() と instanceof

    get_class(class) は、精度がクラス名と等しいかどうかを判断するために使用されます。

  6. instanceof は、それ自体であるか、親クラスから継承しているかを判断できます。
  7. クラス内のメソッドとクラス内の属性

    get_class_methods('クラス名'): クラス内のすべてのメソッドを取得します。

    get_class_vars(' クラス名'): クラス内のすべてのパブリックパラメータを取得します。
  8. リフレクション API

    2 モード

  9. 2.1 組み合わせ
  10. 問題: 教室クラスは講義クラスとセミナー クラスに継承されますが、講義クラスとセミナー クラスの両方に 1 回限りの課金と N クラスの課金を実装するメソッドが必要です。

解決策 1: 教室のクラス メソッドに、1 回払い、N クラスの請求方法、出力計算を計算するメソッドを追加します。

解決策 2: 組み合わせを使用して、請求処理メソッドと出力計算メソッドを請求戦略クラスにカプセル化します。

abstract class Cost_Strategy {    protected $duration;    abstract function cost ();    abstract function charge_type();    public __construct($duration){        $this->duration = $duration;    }}class Timed_Const_Strategy extends Cost_Stratedy {    function cost () {        //上一次课给5块钱- -.        return $this->duration * 5;    }    function charge_type(){        return "多次课结算";    }}class Fixed_Const_Strategy extends Cost_Stratedy {    function cost (){        return 30 ;    }    function charge_type(){        return "一次性课结算";    }}abstract class Leason {    private $cost_strategy;    public __construct(Const_Strategy $cost_strategy){        $this->cost_strategy = $cost_strategy;    }    function __call($method_name,$args){        $args = $cost_strategy ;        if(methood_exists($this->cost_strategy,$method_name)){            return call_user_func_array(                array($this->writer,$method_name),$args);            )        }    }}//运用$leasons[] = new Seminar(new Timed_Const_Strategy(4));$leasons[] = new Lecture(new Fixed_Const_Strategy(null));foreach ($leasons as $leason){    print "leason charge : {$leason->const()}";    print "charge_type : {$leason->charge_type()}"}leason charge 20. charge_type : 多次课结算;leason charge 30. charge_type : 一次课结算;

結合された委任。兄弟委任。

継承された親子関係。

3 オブジェクトを生成する

3.1 シングルトンモード

システム内にユースケースが 1 つだけあることを確認します。たとえば、システム構成ファイル。

キーポイント

1: コンストラクターはプライベートです。

2: クラス自体に独自のインスタンス化プロパティが含まれています。

class Preferences {    private static $instance;    private function __construct(){ ... }    public static function get_instance(){        if(empty(self::$instance)){            self::$instance = new Preferences();        }        return self::$instance;    }    ...}//使用$preferences = Preferences::get_instance();

3.2 ファクトリモード

親クラスを通じて、異なる機能を持つ複数のサブクラスが生成されます。特徴: 製品側 (Sina Weibo) と需要側 (Sina Weibo に表示) の 1 対 1 の対応

問題点 : Evernote では、ソースが Sina Weibo または開発者の Toutiao である可能性があります。 2 つのヘッダーとフッターは異なります

3.3 抽象モード

RLGL!!! .Evernote は Sina Weibo のコンテンツを表示するだけでなく、私の Sina アカウントと Weibo アカウントも表示する必要があります。 ~ 心配しないで、キスしてください

ファクトリーモードは主に 1 対 1 の対応を生成するために使用されます。製品側と需要側、および抽象モデルは需要側 (Evernote_display Sina Weibo) である必要があります。ファクトリー (デマンドサイドを複数のデマンドサイドに抽象化)、たとえば、Sina コンテンツを提供するファクトリー、Sina アカウントに Weibo コンテンツのコメントを提供するファクトリーなどです。

コード:

abstract class Show_Evernote {    abstract function get_header_text();    abstract function get_context();    abstract function get_footer_text();    abstract function get_user();    abstract function get_comment();}class 显示新浪微博 extends Show_Evernote{    function get_header_text(){...};    function get_context(){new 新浪微博_内容;}    function get_footer_text(){...};    function get_user(){new 新浪微博_账号 ;}    function get_comment(){new 新浪微博_评论;}}//使用印象笔记控件类->内容 = 显示新浪微博->get_context;印象笔记控件类->账号 = 显示新浪微博->get_context;...

3.4パラレル モード

ファクトリ/アブストラクト モードを使用する場合、特定のクリエーター (デマンド側) を指定する必要があります

パラレル モードとアブストラクト モードのモデル図は同じですが、コードの実装は異なります。抽象モードでは、親クラスはすべて抽象クラスですが、並列モードでは、すべてのクラスが通常のクラスになるため、親クラスのインスタンス化が容易になります

ここに Evernote クラスを表示するための実装コードをリストします

class Show_Evernote{    private $内容;    private $账号;    private $评论;    function __construct(内容,账号,评论){        $this->内容 = 内容;        $this->账号 = 账号;        $this->评论 = 评论;    }    function get_内容(){        return clone $this->内容);    }    function get_账号(){        return clone $this->账号);    }    function get_评论(){        return clone $this->评论;    }}//使用$factory = new Show_Evernote(     new 新浪微博内容(),    new 新浪微博账号(),    new 新浪微博评论());印象笔记控件类->显示印象笔记 = $factory;

実際には、プロトタイプ モードでは、各コンポーネントのサブクラスをトップレベル クラスでラップするだけであることがわかります。ただし、これにより、たとえば、Sina WeChat ブログ コンテンツの表示を実装するために、それらを簡単に組み合わせることができますが、開発者の Toutiao アカウントを表示する必要がありますか? 4 オブジェクトの使用

4.1 結合モード

結合モードは、結合オブジェクト (集約コンポーネント) を管理する単一のオブジェクトとして理解でき、最終的な結合の下にある各結合コンポーネントは、最も近い型であることが最善です。 、具体性が高いほど、より多くの判断が必要になります

背中を叩く男、足を洗う男、髪を洗う男が 1 人 (女の子) に奉仕するために使用されていると仮定します。女の子のいくつかの部分が利用可能です

//创建一个妹子$妹子 = new 人();//添加洗脚男、捶背男$妹子->add_man(new 洗脚男);$妹子->add_man(new 捶背男);//循环所有男的给予舒服的方法.$妹子->计算舒服程度();

これは理想的な組み合わせモードです。実際には、組み合わせモードを使用する場合、複数のタイプの足洗い男性を作成する必要がある場合があります。

4.2 デコレーションモード

デコレーションモードでは、まず、足を洗う人も、髪を洗う人も、背中を叩く人もすべて人間ですが、男性が叩く場合。彼の背中と髪を洗う、これはどのように機能しますか? add_man 2 回これは非科学的です さあ、この人たちを飾りましょう~

abstract class 人{    ...    abstract function get_well();}   class 男 extends 人 {    //无论你是神马男,服务你,你就能获得10点舒服度.    private $well = 10;    function get_well(){        return $this->well();    }}abstract class 装饰男类型 extends 人 {    protected $人;    function __construct(人 $人){        $this->人 = $人;    } }class 捶背装饰 extends 类型男装饰{    function get_well(){        return $this->人->get_well()+30;    }}class 洗发装饰 extends 类型男装饰{    function get_well(){        return $this->人->get_well()+20;    }}class 洗褪装饰 extends 类型男装饰{    //老子不喜欢别人碰我的毛裤.    function get_well(){        return $this->人->get_well()-20;    }}//创建捶背,能给予的舒服指数 - -嘻嘻.$人 = new 捶背装饰(new 男);$人->get_well(); // 10+30 = 40//来来来,全能选手,捶背、洗发、洗腿一起来$人 = new 洗脚装饰(new 洗发装饰(new 捶背装饰(new 男()))); //10+30+20-20 = 40,注意顺序,由里到外执行.

装饰模式,既(组合+继承),基类方法一定要尽量少,不然子类可能有它不该有的方法.直接类继承,她只可能是一种形态,而她的多种形态可能一并拥有的时候,应该运用组合.

继承即单一多态,组合既多种多态.

这个例子中,你可以添加女,然后把装饰男类型改为装饰通用类型,但每个get_well()都要多一个判断是男还是女(如果给予的舒服程度不一样).

这只是确保不可能出现在男,女之外的第三种人,如果基类为动物,给予服务的可能是鸡,鹅,鸭,那么装饰类型应该运用工厂模式,动物形态和装饰形态一一对应.方便拓展.

除了服务类型,服务男的样子也很重要,这就多了一种装饰,现在有装饰男类型和相貌男类型,这种情况怎么破,其实类似.

//如何获取捶背的帅哥麦?,$人 =new 男类型(new 捶背(new 帅哥麦(new 男())));

4.3 外观模式

即给外部系统提供清晰接口

例如当Model层写得很混乱,但是里面的方法还能用,那我们的Controller层应该列举一些清晰的访问方法来供View层访问.外观模式,强调的是清晰的访问接口.

5 执行任务

5.1 策略模式

给类添加功能.对象要显式的调用它.

继续刚才的洗脚男和人的故事吧…你丫的爽完了要给钱吧?支付宝?微信?现金?

这个付款方式有多种,实现方法不应该放在人类中,而是应该委托给别的类

abstract class 人 {    protectd $支付方式;    function set_支付方式(){...}    function 付款(金额){        return $支付方式->付款($金额);    }}abstract class 付款{    abstract function 付款($金额);}class 支付宝付款 extends 付款{    function 付款($金额){        return 外接支付宝付款流程($金额);    }}...//使用$男 =new 男();///爽爽爽...//结账$支付宝支付账单 = new 支付宝付款($金额);$人 = new 男();$人->set_支付方式(new 支付宝付款());$人->付款();

5.2 观察者模式

当被观察者发生变化,观察者需要被通知.

当数据发生变化,页面需要被通知.

使用步骤:

  1. 观察者加载到被观察者中.
  2. 被观察者通知观察者.

例如登陆类(被观察)状态改变,要出发邮件系统和日志系统(观察者)

interface 被观察者{    function attach(观察者);    function detatch(观察者);    function notify();}class Login implements 被观察者{    private $观察者;    function __construct(){        $this->观察者 = array();    }    function attach($观察者){        $this->观察者 = $观察者;     }    function detach($观察者){        //删除某个观察者的操作;    }    function notify(){        foreach ($this->观察者 as $单个观察者){            $单个观察者->update($this);        }    }       }interface 观察者{    function update(被观察者);}abstract class Login_观察者 implements 观察者{    private $login;    function __construct (Login $login){        $this->login = $login;        $login->attach($this);    }    function update(观察者 $观察者){        if ($观察者 ===$this->login){            $this->do_update($观察者);        }    }    abstract function do_update(Login $login);}class 邮件观察者 extends 登陆观察者 {    function do_update(Login $login){        //判断条件 发送邮件    }}class 日志观察者 extends 登陆观察者 {    function do_update(Login $login){        //判断条件 记录到日志;    }}//使用$login = new Login();new 邮件观察者 ($login);new 日志观察者 ($login);

PHP有内置的SPL实现上述的观察者模式.

5.3 访问者模式

问题: 在一个军队中,有很多军队,军队下面可能包含军队/步兵/弓箭手,这时我们要显示一个军队的战斗力/需要粮食的各级分配?(遍历对象并设置显示方法).怎么办?.解决办法是军队还是保存自己的基本信息,设置一个访问者,访问者包含总战斗力方法和总粮食的方法.

访问者

abstract class 军队访问者{    abstract function 访问(单元);    function 访问军队($军队){         $this->访问($军队);    }    function 访问弓箭手($弓箭手){        $this->访问($弓箭手);    }    //这里重复定义了大量代码,其实可以用call来替代    function __call($method_name,$args){        if(strrpos($method_name, "访问")){            return call_user_func_array(                array($this,"访问"),$args            );        }    }}class 军队战斗力访问者 extends 军队访问者{    private $text="";    function 访问($单元){        $ret = "";        $pad = 4*$单元->getDpth(); //设置显示深一级前面多4个空格.        $ret .= sprintf( "%{$pad}s","");        $ret .= get_class($单元). ": ";        $ret .= "战斗力: " .$单元->bombardStrenth()."n";        $this->text .=$ret;    }    function get_text(){        return $this->text;    }}

被访问者

abstract class 单元{    function 接受($军队访问者){        $method = "访问_".get_class($this);        $军队访问者->$method($this);    }    private $depth;    protected function set_depath($depth){        $this->depth=$depth;    }    function get_depth(){        return $this->depth;    }    ...}abstract class 综合单元 extends 单元{    function 接受($军队访问者){        parent::接受($军队访问者)        foreach($this->单元集合 as $this_unit){            $this->unit->接受($军队访问者);        }    }}class 军队 extends 综合单元{    function bombardStrenth(){        $ret =0;        foreach($this-units() as $unit){            $ret += $unit->bombardStrenth();        }        return $ret    }}class 弓箭手 extends 单元{    function bombardStrenth(){        return 4;    }}

调用

$main_army = new Army();$main_army->add_unit(new 步兵());$main_army->add_unit(new 弓箭手());$军队战斗力访问者_实例 =new 军队战斗力访问者();$main_army->接受(均分战斗力访问者);print $军队战斗力访问者->get_text();

输出

军队: 战斗力: 50    步兵: 攻击力 :48    弓箭手: 攻击力: 4

5.4 命令模式

例子为Web页面的login和feed_back,假如都需要使用ajax提交,那么问题来了,将表单封装好提交上去,得到了返回结果.如何根据返回结果跳转不同的页面?.

有些同学就说了,login和feed_back各自写一个方法憋,提交的时候调用各自的方法.

然后再来个logout命令..增加..删除..命令怎么办..

命令模式比较适合命令执行例如登陆,反馈等简单只需要判断是否成功的任务

命令:

abstract class Command{    abstract function execute(Conmmand_Context $context);}class Login_Command extends Command{    function execute(CommandContext $context){        $managr =Register::getAccessManager();        $user = $context->get("username");        $pass = $context->get('pass');        $user_obj = $manager->login($user,$pass);        if(is_null($user_obj)){            $context->setError($manager->getError());            return false;        }        $context->addParam("user",$user_obj);        return true;    }}

部署命令的调用者

class Command_Facotry{    public function get_command($action){        $class = UCFirst(strtolower($action))."_Command";        $cmd = new $class();        return $cmd;    }}

客户端

class Controller{    private $context;    function __construct(){        //Command_Context主要用来存储request和params        $this->context =new Command_Context();    }    function process(){        $cmd Command_Factory::get_commad($this->context->get('action'));        if(!$cmd-execute($this->context)){            //错误处理        }else{            //成功 分发视图        }    }}

使用

$controller =new Controller();$context = $controller->get_context();$context->add_param('action','login');$context->add_param('username','404_k');$context->add_param('pass','123456');$controller->process();

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