>웹 프론트엔드 >JS 튜토리얼 >심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술

심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술

WBOY
WBOY원래의
2016-05-16 15:15:191208검색

1 문법

1.1 기본 문법

클론

원본 개체를 조작해야 하지만 원본 개체에 영향을 주고 싶지는 않습니다.

코드 복사 코드는 다음과 같습니다.

$K_back = $K 복제;

기본 데이터 유형과 배열은 모두 실제 복사본입니다. 즉, 속성이 개체인 경우 복사본을 변경해도 원본 개체에 영향을 줍니다.

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

__clone은 복제 전에 자동으로 트리거되며 백업 전에 일부 속성 작업을 수행할 수 있습니다.

2. & 합격 참고

메서드 참조 전달, 소스 객체 변경

코드 복사 코드는 다음과 같습니다.

함수 set_K(& $K){...}
함수 & get_K(){...}

3. 정적 지연 정적 바인딩

애플리케이션 시나리오: Dog 클래스와 Person 클래스 모두 인스턴스화를 반환하는 메서드가 필요합니다. Dog 클래스와 Person 클래스는 모두 Animal 추상 클래스에서 상속됩니다.

abstract class Animal{
  public static function create(){
    //实例化调用类
    return new static();
  }
}

class Person extends Animal{...}

//返回Person实例化类
Person::create();

4. 인터셉터

__get($property), 정의되지 않은 속성에 액세스할 때 호출됩니다.
__set($property,$value), 정의되지 않은 속성에 값을 할당할 때 호출됩니다.
__isset($property), 정의되지 않은 속성에 대해 isset() 메서드를 호출할 때 호출됩니다.
__unset($property), 정의되지 않은 속성에 대해 unset() 메서드를 호출할 때 호출됩니다.
__call($method,$arg_array), 정의되지 않은 메소드를 호출할 때 호출됩니다.
__call은 매우 유용하지만 너무 유연하므로 주의해서 사용하세요.
응용 시나리오: Person 클래스 정보를 구체적으로 인쇄하는 Person_Writer 클래스가 있습니다. Person_Writer 클래스가 Person 클래스를 통해 호출되는 경우.

//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);
      )
    }
  }

} 

5. 콜백 기능

적용 시나리오: Product 클래스, Product_Sale 클래스, Product_Totalizer 클래스 3개 클래스 구현 예정: 상품 판매 총액이 지정된 금액을 초과하면 경고가 출력됩니다.

//Product
class Product {
  public $name;
  public $price;
}

//Product_Sale
class 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_Totalizer
class 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块啦~

6. get_class() 및 인스턴스

get_class(class)는 클래스 이름과 정확히 동일한지 확인하는 데 사용됩니다.

instanceof는 자신이 자신인지 아니면 상위 클래스에서 상속되는지를 결정할 수 있습니다.

7. 클래스의 메서드와 클래스의 속성

코드 복사 코드는 다음과 같습니다.

get_class_methods('클래스 이름'): 클래스의 모든 메소드를 가져옵니다.
get_class_vars('class name'): 클래스의 모든 공개 매개변수를 가져옵니다.

8. 반사 API

2가지 모드

2.1 조합

문제: 강의실 수업은 강의 수업과 세미나 수업을 모두 상속받습니다. 그런데 강의 수업과 세미나 수업 모두 일회성 청구 방식과 N등급 청구 방식을 구현해야 합니다.

해결 방법 1: 일회성 결제 방식, N레슨에 대한 청구 방식, 수업수업에서 계산 방식을 출력하는 방식을 추가합니다.

해결책 2: 조합을 사용하여 청구 처리 방법과 출력 계산 방법을 청구 전략 클래스로 별도로 캡슐화합니다.

심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술

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: 생성자는 비공개입니다.

2: 클래스 자체에는 자체 인스턴스화 속성이 포함되어 있습니다.

심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술

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 공장 모드

하나의 상위 클래스를 사용하여 다양한 기능을 가진 여러 하위 클래스를 생성합니다.

특징: 상품측(시나 웨이보)과 수요측(시나 웨이보 표시) 간 1:1 대응

문제: Evernote에서 소스가 Sina Weibo 또는 개발자 Toutiao일 수 있습니다. Evernote가 표시될 때 둘의 머리글과 바닥글이 다릅니다.

심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술

3.3 추상 패턴

RLGL!!!. Evernote는 시나 웨이보 콘텐츠만 표시해야 하는 것이 아니라 내 시나 계정과 웨이보도 표시해야 합니다!! 젠장~ 걱정하지 말고 키스해 주세요.

공장 모델은 주로 제품 측과 수요 측 간의 일대일 대응을 생성하는 데 사용되는 반면, 추상 모드는 수요 측(Evernote_display Sina Weibo)을 의도하여 여러 공장이 필요합니다(수요 추상화). 시나 콘텐츠를 제공하는 공장, 시나 계정을 제공하는 공장, 웨이보 콘텐츠에 댓글을 제공하는 공장 등

심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술

코드:

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 平行模式

当使用工厂/심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술必须要制定具体的创建者(需求方).

平行模式和심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술的模型图一致,但代码实现不一样.

심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술中父类均为抽象类,而平行模式中,所以类都为普通类,方便父类的实例化.

在这里列出显示印象笔记类的实现代码

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;

其实大家可以发现,原型模式只不过只在最顶层类中包装了一下各组件子类而已,然而这样可以轻松的组合他们,例如实现一个显示新浪微博内容,但要显示开发者头条账号的需求?

4 使用对象
4.1 심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술

심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술,可以理解为单一对象管理组合对象(聚合组件),最终组合体下的各个组合部件最好类型一致.不然特殊性越多,需要判断就越多.

假设捶背男,洗脚男,洗发男,用来服务一个人(妹子).

假设妹子的几个部位可用的服务男均为无限个.

심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술

//创建一个妹子
$妹子 = new 人();

//添加洗脚男、捶背男
$妹子->add_man(new 洗脚男);
$妹子->add_man(new 捶背男);

//循环所有男的给予舒服的方法.
$妹子->计算舒服程度();

这是一个很理想的심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술,在现实情况,我们使用심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술,可能不得不创建多种类型的洗脚男,需要添加许多判断条件.

4.2 심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술

심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술,首先洗脚男,洗发男,捶背男都是人,但是如果,一个男的又捶背,又洗发,这怎么玩?.add_man两次?这不科学吧,来给这些男的装饰一下吧~

심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술

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,注意顺序,由里到外执行.

심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술,既(组合+继承),基类方法一定要尽量少,不然子类可能有它不该有的方法.直接类继承,她只可能是一种形态,而她的多种形态可能一并拥有的时候,应该运用组合.

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

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

这只是确保不可能出现在男,女之外的第三种人,如果基类为动物,给予服务的可能是鸡,鹅,鸭,那么装饰类型应该运用심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술,动物形态和装饰形态一一对应.方便拓展.

除了服务类型,服务男的样子也很重要,这就多了一种装饰,现在有装饰男类型和相貌男类型,这种情况怎么破,其实类似.심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술

复制代码 代码如下:

//如何获取捶背的帅哥麦?,
$人 =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 심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술

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

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

使用步骤:

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

심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술

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

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实现上述的심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술.

5.3 심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술

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

심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술

访问者

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 심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술

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

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

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

심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술比较适合命令执行例如登陆,反馈等简单只需要判断是否成功的任务

심층적인 PHP 객체지향, 패턴 및 사례_javascript 기술

命令:

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으로 문의하세요.