5

私は、可能な限り強くタイプしようとしているフレームワークに取り組んでいます。(私は PHP 内で作業しており、C# から好きなアイデアを取り入れて、このフレームワーク内でそれらを利用しようとしています。) ドメイン エンティティ/オブジェクトのコレクションである Collection クラスを作成しています。List<T>.Netのオブジェクトをモデルにしています。

このクラスの入力を妨げている障害に遭遇しました。UserCollection がある場合は、User オブジェクトのみを許可する必要があります。PostCollection がある場合は、Post オブジェクトのみを許可する必要があります。

このフレームワークのすべてのコレクションには、追加、削除、反復などの特定の基本機能が必要です。インターフェイスを作成しましたが、次のことができないことがわかりました。

interface ICollection { public function add($obj) }
class PostCollection implements ICollection { public function add(Post $obj) {} }

これにより、インターフェースへの準拠が破られました。しかし、すべてのコレクションが同じ型であるため、インターフェイスを厳密に型指定することはできません。そこで、次のことを試みました。

interface ICollection { public function add($obj) }
abstract class Collection implements ICollection { const type = 'null'; }
class PostCollection extends Collection {
 const type = 'Post';
 public function add($obj) {
  if(!($obj instanceof self::type)) {
   throw new UhOhException();
  }
 }
}

このコードを実行しようとするとsyntax error, unexpected T_STRING, expecting T_VARIABLE or '$'instanceofステートメントが表示されます。$obj instanceof selfこの問題を少し調査したところ、原因の根本は、クラスに対してテストするのに有効であるように見えます。PHP はself::type、式内の定数ステートメント全体を処理していないようです。変数を括弧で囲むとself::type、予期しない「(」に関するエラーがスローされました。

明らかな回避策は、type変数を定数にしないことです。式$obj instanceof $this->typeは問題なく機能します ($typeもちろん変数として宣言されている場合)。

後で変数が変更される可能性を避けるために、値を定数として定義したいので、それを回避する方法があることを願っています。どうすればこれを達成できるか、またはこの点でPHPを限界まで持っていますか? self::this処理中にPHPが死なないように「エスケープ」またはカプセル化する方法はありますか?

更新以下のフィードバックに基づいて、試してみることを考えました-以下のコードが機能します! 1) これをしない理由、2) これが最終的に機能しない理由、または 3) これをやってのけるためのより良い方法を考えられる人はいますか?

interface ICollection { public function add($obj) }
abstract class Collection { const type = null; protected $type = self::type; }
class PostCollection extends Collection {
 const type = 'Post';
 public function add($obj) {
  if(!($obj instanceof $this->type)) {
   throw new UhOhException();
  }
 }
}

更新 #2:上記のコードを本番環境に置いた後、動作しないことが判明しました。テストしたときにどのように機能したかわかりませんが、まったく機能しません。私はprotected変数の使用にこだわっていると思います。

4

6 に答える 6

3

別の回避策は次のとおりです。

$type = self::type;
if (!($obj instanceof $type))

定数だからといって、パーサーを満足させるために一時的に変数に入れることができないわけではありません。

于 2010-06-09T01:41:53.227 に答える
2

ドメインエンティティ/オブジェクトのコレクションであるCollectionクラスを作成しています。List<T>.Netのオブジェクトをモデルにしています。

一般に、ある言語を別の言語で書くことはお勧めできません。PHPのコレクションは必要ありません。

その道を進む場合は、PHPから提供されたツールの使用を検討する必要があります。たとえば、ArrayObjectがあります。これを継承し、必要なメソッドをオーバーライドして、適切に型指定されたものだけが配列に入るようにすることができます。ArrayObjectsは、通常の配列を使用できるPHPのどこでも使用できます。また、基礎となる断片はすでにあなたのために書かれています。

標準PHPライブラリの残りの部分、特にSplObjectStorageクラスはあなたにとって興味深いかもしれません。

于 2010-06-09T03:02:29.387 に答える
2

私はこの動作にも驚いていますが、これはうまくいくはずです:

$type = self::type;
if(!($obj instanceof $type)) {
    throw new UhOhException();
}

編集:

あなたができる

abstract class Collection {
    const type = null;
    protected $type = self::type;
}
class PostCollection extends Collection {
    const type = "User";
    public function add($obj) {
        if(!($obj instanceof $this->type)) {
            throw new WhateverException();
        }
    }
}

しかし、あなたは共犯計をオンにしています。$typeこれには、インスタンスごとにインスタンス変数を作成するという追加のオーバーヘッドがあります (いいえ、プロパティに追加するPostCollectionことはできません)。static$type

于 2010-06-09T01:41:38.593 に答える
1

すぐにこのようになるはずです

public function add(ICollection $obj){

}

Icollection のインスタンスではない関数 add にオブジェクトを追加しようとすると (これは例です)、instanceof を使用してチェックする前に失敗します。

于 2010-06-09T09:31:36.057 に答える
0

これも静的を使用して正しく機能します。

<?php

interface ICollection { 
  public function add($obj); 
}
abstract class Collection implements ICollection { 
  static protected $_type = 'null'; 
}
class PostCollection extends Collection {
 static protected $_type = 'Post';
 public function add($obj) {
  if(!($obj instanceof self::$_type)) {
   throw new UhOhException();
  }
 }
}


class Post {}

$coll = new PostCollection();
$coll->add(new Post());

そして実際には、おそらくとにかくクラスadd()でメソッドを定義したいでしょう。つまり、何らかの奇妙なことを回避するために使用する必要があるか、とにかく常に基本クラスを返したいので、これはおそらくうまくいくでしょう:Collectionget_class()self::typeself::$_typeCollection

abstract class Collection implements ICollection { 
  const type = 'null'; 
  public function add($obj) {
   $c = get_class($this);
   $type = $c::type;
   if(!($obj instanceof $type)) {
    throw new UhOhException();
   }
  }
}

class PostCollection extends Collection {
 const type = 'Post';
}
class Post {}

$coll = new PostCollection();
$coll->add(new Post());
于 2010-06-09T09:40:19.563 に答える
-1

クラス名として文字列が必要なため、instanceof の代わりにPHP のis_a関数を使用してみてください。

于 2010-06-09T01:45:36.370 に答える