3

次のようにクラスを構築するときに、クラスを拡張できることを知っています。

class b extends a {
}

しかし、スクリプトからクラスを動的に拡張することは可能ですか? そのような:

$b = new b($input) extends a;

私が達成したいのは、公開ページではなく管理者で使用されるかどうかにかかわらず、モジュールを異なる方法で拡張することです。同じ名前で 2 つの異なる親クラスを作成し、管理者またはパブリックごとに 1 つだけ含めることができることを知っています。しかし、私の質問は、PHP で動的に行うことは可能ですか?

4

7 に答える 7

3

いいえ、RunKit のような拡張機能がないわけではありません。

別のアプローチを検討することもできます。B に A の機能を引き継がせたい場合は、おそらく次のようなものが一種の「ミックスイン」アプローチを提供できます。全体像は、B が A の子ではなく、B が A に委譲するというものです。

<?php

class MixMeIn
{
  public $favouriteNumber = 7;

  public function sayHi() {
    echo "Hello\n";
  }
}

class BoringClass
{
  private $mixins = array();

  public function mixin($object)
  {
    $this->mixins[] = $object;
  }

  public function doNothing() {
    echo "Zzz\n";
  }

  public function __call($method, $args)
  {
    foreach ($this->mixins as $mixin)
    {
      if (method_exists($mixin, $method))
      {
        return call_user_func_array(array($mixin, $method), $args);
      }
    }
    throw new Exception(__CLASS__ + " has no method " + $method);
  }

  public function __get($attr)
  {
    foreach ($this->mixins as $mixin)
    {
      if (property_exists($mixin, $attr))
      {
        return $mixin->$attr;
      }
    }
    throw new Exception(__CLASS__ + " has no property " + $attr);
  }

  public function __set($attr, $value)
  {
    foreach ($this->mixins as $mixin)
    {
      if (property_exists($mixin, $attr))
      {
        return $mixin->$attr = $value;
      }
    }
    throw new Exception(__CLASS__ + " has no property " + $attr);
  }

}

// testing

$boring = new BoringClass();
$boring->doNothing();
try {
  $boring->sayHi(); // not available :-(
}
catch (Exception $e) {
  echo "sayHi didn't work: ", $e->getMessage(), "\n";
}
// now we mixin the fun stuff!
$boring->mixin(new MixMeIn());
$boring->sayHi(); // works! :-)
echo $boring->favouriteNumber;

ただのばかげた考え。質問を正しく理解できたと思います。

于 2012-05-06T05:38:05.937 に答える
2

できませんが、これは数年前から要求されています: https://bugs.php.net/bug.php?id=41856&edit=1

eval 内でクラスを定義することはできますが、クラスを通常どおりに宣言するよりも面倒です。

于 2012-05-06T05:34:45.543 に答える
1

または、JavaScript スタイルの継承に慣れていて、型チェックが失われても構わない場合は、次のようにします。

<? //PHP 5.4+
final class ExpandoLookalike {
    //Allow callable properties to be executed
    public function __call($name, $arguments) {
        \call_user_func_array($this->$name, $arguments);
    }
}

$newBaseModule = static function(){
  $base = new ExpandoLookalike();
  //Common base functions get assigned here.
  $basePrivateVar = 42;

  $base->commonFunction = static function($params1, $params2) use ($basePrivateVar){
      echo "common function\n";
  };
  $base->comment = static function() use ($basePrivateVar){
    echo "Doing base comment with $basePrivateVar\n";
  };
  return $base;
};

//Javascript-style extends
$newAdminModule = static function($param) use ($newBaseModule){
  $base = $newBaseModule();

  $privateVar = 5;


  $base->adminProperty = 60;
  $base->suspendSite = static function() use ($param, $privateVar){
    echo 'Doing admin only function ';
    echo "with $param, $privateVar\n";

  };

  return $base;
};


$newPublicModule = static function() use ($newBaseModule){
  $base = $newBaseModule();

  $privateVar = 3;

  //Javascript-style overloading
  $oldComment = $base->comment;
  $base->comment = static function($data) use ($oldComment, $privateVar){
    $oldComment();
    echo 'Doing public function ';
    echo "with $data\n";
  };

  return $base;
};

$baseModule = $newBaseModule();
$adminModule = $newAdminModule('P');
$publicModule = $newPublicModule();

$adminModule->suspendSite(); //echos 'Doing admin only function with P, 5'
echo "{$adminModule->adminProperty}\n"; //echos '60'
$publicModule->comment('com'); //echos 'Doing base comment with 42'
                                     //'Doing public function with com'
?>

トレイトとインターフェースへの扉は閉ざされていますが、それを補うために他の興味深い扉が開かれています。

<? //PHP 5.4+

$inheritAllTheThings = static function(){
  $base = new ExpandoLookalike();
  foreach(\func_get_args() as $object){
    foreach($object as $key => $value){
        //Properties from later objects overwrite properties from earlier ones.
        $base->$key = $value;
    }
  }
  return $base;
};

$allOfEm = $inheritAllTheThings(
  $newPublicModule(),
  $newAdminModule('Q'),
  ['anotherProp' => 69,]
);

$allOfEm->comment('f'); //echos 'Doing base comment with 42'
//Because AdminModule came after PublicModule, the function that echos 'f'
//from PublicModule was overridden by the function from AdminModule.
//Hence, order denotes resolutions for multiple inheritance collisions.
$allOfEm->suspendSite(); //echos 'Doing admin only function with Q, 5'
echo $allOfEm->anotherProp . "\n"; //echos '69'

?>
于 2012-05-06T06:59:15.907 に答える
1

extendsただし、オブジェクトの作成中は使用できません。extendsクラス定義でのみ使用され、他のどのクラスが新しいクラスの「親」であるかを定義します。

于 2012-05-06T05:25:10.863 に答える
0

はい、コーリーが言ったように、この機能は以前にリクエストされました。ただし、その前に、回避策を作成できます。これが私の古い学校のトリックです

次のような 2 つの個別のクラスを作成します。

class a {
}
class b {
   public $object;
}

次に、拡張バージョンも作成します

class bextendeda extends a {
}

クラス b のコンストラクタ メソッドでは、要求された場合に拡張オブジェクトにリダイレクトする関数をいくつか配置します。

class b {
    public $object;

    public function __contruct($extend = false) {
        if($extend) $this -> object = new bextendeda(); 
        else $this -> object = $this;
    }

    function __get($prop) {
        return $this-> object -> $prop;
    }

    function __set($prop, $val) {
       $this-> object -> $prop = $val;
    }
    function __call($name, $arguments)
    {
        return call_user_func_array(array($this -> object, $name), $arguments);
    }

}

拡張バージョンが必要な場合は、これを行うだけです

$b = new b(true);

そうでない場合

$b = new b();

楽しみ :)

于 2012-05-06T05:40:41.897 に答える
0

型キャストでできます。a が b を拡張する場合、次のことができます

$a=(a)(new b($input));

まったく同じではありませんが、似ています。

于 2012-05-06T05:22:14.210 に答える
0

あなたが見ることができます:https://github.com/ptrofimov/jslikeobject

作成者は、継承をサポートする JS に似たオブジェクトを実装しました。

しかし、通常のオブジェクトの代わりにそのようなオブジェクトを使用するのはあまり良くないかもしれません。

于 2013-01-08T18:24:20.950 に答える