2009-05-20 5 views
11

オーバーライドされた別の静的関数 "inner"を呼び出すために、継承された静的関数 "call"が必要です。遅い静的バインディングでこれを行うことはできますが、私のホストにはまだphp5.3がないので、回避する必要があります。フェイク遅い静的バインディングphpの前に5.3

class ClassA{ 
    static function call() 
    { 
     return self::inner(); 
    } 

    static function inner(){ 
     return "Class A"; 
    } 
} 

class ClassB extends ClassA{ 
    static function inner(){ 
     return "Class B"; 
    } 
} 

echo "<p>Class A = " . ClassA::call(); 
echo "<p>Class B = " . ClassB::call(); 

私はあることを出力したいと思います:
クラスA =クラスA
クラスB =クラスB

しかし、それが何であるか:
クラスA =クラスA
クラスB =クラスA

「コール()」が呼び出されたときに、どのオブジェクトが参照されたかを検出するためにcall()に何かを書くことができるはずです。したがってself :: inner()の代わりに、calledclass :: inner()の行に沿って何かがあります。元のメソッド呼び出しから呼び出すための適切なバージョンのinner()を検出します。

+0

あなたのホストはFatCowですか?今は2012年6月ですが、PHP 5.3はまだありません。 FatCowでは-1です。 – Ben

答えて

1

クラスではなくオブジェクトインスタンスを使用できます。グローバルシンボルが必要な場合は、グローバル変数を使用できます。 PHPでは扱いにくいので、1つのトリックは関数にラップすることです。例:

class ClassA { 
    function call() { 
    return $this->inner(); 
    } 
    function inner() { 
    return "Class A"; 
    } 
} 
function ClassA() { 
    static $instance; 
    return $instance ? $instance : new ClassA(); 
} 

class ClassB extends ClassA { 
    function inner() { 
    return "Class B"; 
    } 
} 
function ClassB() { 
    static $instance; 
    return $instance ? $instance : new ClassB(); 
} 

echo "<p>Class A = " . ClassA()->call(); 
echo "<p>Class B = " . ClassB()->call(); 

しかし、より良い考え方はグローバルシンボルを完全に避けることです。 Ruby/Railsでうまく動作するのは、RubyがPHPと同じように静的な状態を持っていないからです。実行時にクラスをリバウンドして追加することができ、フレームワークを簡単に拡張できます。 PHPでは、クラスは常に最終的なものなので、アプリケーションコードでクラスを参照することは、非常に強い結合度です。

+1

また、シングルトンを使用し、静的関数getInstance()でインスタンスコードをラップし、関数classB()を返すこともできます(return classB :: getInstance(); } –

1

残念ながら、それを行うには良い方法はありません(そうでなければ、その機能のためには非常に熱望しません)。

お客様には、のパスクラス名が必要です。 PHP < 5.3はまた、全体のことをしても醜いなります動的クラス名を持つ静的呼び出しのための素敵な構文を持っていない:あなたは(staticを使用していない)のコードを変更することができる場合

static function call($class) 
{ 
    return call_user_func(array($class,"inner")); 
} 
… 
ClassA::call("ClassA"); 
ClassB::call("ClassB"); 

、その後、シングルトンはそれがより我慢します。あなたは、構文を容易にするためのヘルパー機能を行うことができます。

X("ClassA")->call(); 
X("ClassB")->call(); 

X機能は、見上げる作成したクラスのインスタンスを返す必要があります。

+1

したがって、基本的にコードを構造化することでこの問題を完全に回避して、これを行う必要はなく、5.3まで待つことができますか?吸う。 –

3

パフォーマンスが問題ではない場合、あなたは(debug_backtraceを使用することができますが)というクラスを見つけるために:

$bt = debug_backtrace(); 
return get_class($bt[1]['object']); 

http://php.net/manual/en/function.debug-backtrace.php

+0

これはPHP 5.2で呼び出された実際のクラスを提供しません –

1

多くの場合、子供は方法をコールバックするとき結合後半静的が必要とされています親は、順番に、子どもの抽象的な静的メソッドを呼び出します。私はPHPがバージョン5.3(またはそれ以降)ではなかったので、私はそのような後退にあったし、静的::を使用できませんでした。 debug_backtrace()を使用して、次の遅延バインディングが完成しました。

abstract class ParentClass 
{ 
    static function parent_method() 
    { 
     $child_class_str = self::get_child_class(); 
     eval("\$r = ".$child_class_str."::abstract_static();"); 
     return $r; 
    }// CHILD MUST OVERRIDE TO PUT ITSELF INTO TRACE 

    protected abstract static function abstract_static(); // THIS NEEDS LATE STATIC BINDING 

    private static function get_child_class() 
    { 
     $backtrace = debug_backtrace(); 
     $num = count($backtrace); 
     for($i = 0; $i < $num; $i++) 
     { 
      if($backtrace[$i]["class"] !== __CLASS__) 
        return $backtrace[$i]["class"]; 
     } 
     return null; 
    } 
} 

class ChildClass extends ParentClass 
{ 
    static function parent_method(){ return parent::parent_method(); } 

    protected static function abstract_static() 
    { 
     return __METHOD__."()"; 
    }// From ParentClass 
} 

print "The call was: ". ChildClass::parent_method(); 
0

あなたは他の回答で述べたように との何らかの指示というクラス(と内側の()関数を呼び出す必要があります 、静的::、またはget_called_class()、または__callStaticを使用傾けるので、 )。呼び出されたクラスのインスタンス は問題ありません。 "疑似静的"メソッドを追加すると、すべての静的メソッド を上書きする必要があります。これはあなたのコードを二倍にしますが、 を以下のようにすることで、 php5.3が一度にアップグレードされるとコードが簡単にアップグレードされることを願っています:psのメソッドと、 )必要に応じて「静的」に変更してください。

class ClassA{ 
    static function call() 
    { 
     return self::inner(); 
    } 

    static function inner(){ 
     return "Class A"; 
    } 

    public function _ps_call() 
    { 
     return $this->_ps_inner(); 
    } 


} 

class ClassB extends ClassA{ 

    public static function getInstance() 
    { 
     return new self(); 
    } 

    public static function call() 
    { 
     return self::getInstance()->_ps_call(); 
    } 

    static function inner() 
    { 
     return "Class B"; 
    } 

    public function _ps_inner() 
    { 
     return self::inner(); 
    } 
} 

echo "<p>Class A = " . ClassA::call(); 
echo "<p>Class B = " . ClassB::call(); 
+0

。静的な変数をこの例に追加するとさらに精巧になります。 getInstance()メソッドでは、すべてのget_class_varsを$ this - > _ ps_fooのようなインスタンス変数にコピーできます。これは、すべての_ps_インスタンスメソッド内で静的バージョンの代わりに使用する必要があります。 – commonpike

2

ここでは簡単な例を示します。

<?php 

class ClassA{ 
    public function call(){ 
     return $this->inner(); 
    } 

    static function inner(){ 
     return "Class A"; 
    } 

    static function init($class){ 
     return new $class(); 
    } 
} 

class ClassB extends ClassA{ 
    static function inner(){ 
     return "Class B"; 
    } 
} 

echo "<p>Class A = " . ClassA::init("ClassA")->call(); 
echo "<p>Class B = " . ClassB::init("ClassB")->call(); 

?> 

あなたは子クラスに静的なinit関数を追加して、明示的にもそこにそれを渡すことができ、クラス名を渡して好きではない場合。これは、ClassA :: init() - > call()とClassB :: init() - > call()のようなことを可能にしますが、マイナーコードの重複があります。