2013-05-21 2 views
8

それを動作させる方法はありますか?例を参照してください:PHPのクラス置換

class car { 
     function __construct($type){ 
       switch ($type) { 
         case 'big' : return new big_car(); 
         case 'small' : return new small_car(); 
       } 
     } 
     function whatisit() { 
       echo "this is car ;(\n"; 
     } 
} 

class big_car extends car { 
     function __construct(){} 
     function whatisit() { 
       echo "this is big car ;) \n"; 
     } 
} 

class small_car extends car { 
     function __construct(){} 
     function whatisit() { 
       echo "this is small car ;) \n"; 
     } 
} 

ので、目標はこのようにそれを使用することです。

$mycar = new car('big'); 
$mycar->whatisit(); // i want it to say that it's big 

私はその悪い道、非常に多くを推測し、それがこのように動作することはできませんが、多分トリックはありますか?

PSは::私はそのための特別な静的メソッドを使用することができます知っているが...

+0

コンストラクタは、PHPの値を返すことはできません。別の方法が必要です。 – NullUserException

+0

ニックネーム+アバターのために@kitty upvoted。 – moonwave99

+0

"car"インターフェイスと "car"ファクトリを追加する必要があります。両方を一緒に実行しようとすると、醜くて難しくなります。 – Xeoncross

答えて

9

あなたは新しい車を作成するために自動車工場を必要とします。これはJavaScriptではありません:)

class car_factory 
{ 
    function create_car($type = null) 
    { 
     switch ($type) { 
      case 'big': 
       return new big_car(); 

      case 'small': 
       return new small_car(); 

      case null: 
       return new car(); 
     } 
     throw new InvalidArgumentException($type); 
    } 
} 

$factory = new car_factory; 
$small_car = $factory->create_car('small'); 
$std_car = $factory->create_car(); 

もちろん、元のコードから__construct関数を削除する必要があります。

コメントにmentionedとして、あなたは完全にクラスの拡張が同じコンストラクタとクラスの命名に一貫性がある持っていると仮定すると、動的なクラスを使用してこれを一般化できます。

class car_factory 
{ 
    function create_car($type = null) 
    { 
     if (is_null($type)) { 
      return new car(); 
     } 

     $class = "{$type}_car"; 
     if (class_exists($class)) { 
      $obj = new $class(); 

      if ($obj instanceof car) { 
       return $obj; 
      } 
     } 

     throw new InvalidArgumentException($type); 
    } 
} 

は個人的に私は好みのいずれかの方法がありません。拡張性が重要な要素ならば、それに気をつけてください。そうでない場合は、単純なswitchを付けてください。

+0

彼が望むやり方をするには、例外をスローするのではなく、引数が 'big'または' small'でないときに 'new car();を返すべきだと私は信じています。 – Paulpro

+0

@Paulpro良い点:)が追加されました。 –

+0

見栄えいいです:)素敵な編集。 – Paulpro

1

[...]あなたは完全に同じコンストラクタとクラスの命名は

一致している必要がありますが、リフレクションを使用していても、より多くの柔軟性を追加することができ、クラスの拡張を想定し、動的なクラスを使用してこれを一般化できます。

class car_factory 
{ 
    function create_car($class = null, $constructorArgs = array()) 
    { 
     if (is_null($class)) { 
      return new car(); 
     } 

     try { 
      $refl = new ReflectionClass($class); 
      if (!$refl->isSubclassOf('car') { 
       throw new DomainException("Type: {$class} is not a car type"); 
      } 
      return $refl->newIntanceArgs($constructorArgs); 
     } catch(ReflectionException $e) { 
      throw new DomainException("Invalid car type: {$class}"); 
     } 
    } 
} 

は今使用します。

$factory = new car_factory(); 
$car1 = $factory->create_car('big_car'); 
$car2 = $factory->create_car('small_car'); 
$car3 = $factory->create_car('fancy_car_name_with_constructor_args', array("I'm fancy!")); 
+0

また、オブジェクトを渡すだけなら、relfectionをスキップして 'type-hinting'を使うこともできます:' function __construct(\ Car $ car){$ this-> car = $ car; } ' – Xeoncross

+0

この場合、オブジェクトをインスタンス化して工場に渡す必要があります。したがって、工場は何ですか? –

+0

はい、私はこの特定の事例について話していませんでした - この回答を読んでいる人なら誰でも投稿してください。とにかくテストの方が良いと思われる工場パターンではなく、実際にはDIデザインです。 – Xeoncross