8

この質問の形式で何かを試すつもりです。それを処理するためのより良い方法についての提案を非常に歓迎しています。

質問で大量のコードをダンプしたくなかったので、クラスのコードを に投稿しましたrefactormycode

クラス プロパティを簡単に処理するための基本クラス

私の考えでは、人々はここにコード スニペットを投稿するか、変更を加えrefactormycodeてリファクタリングへのリンクを投稿することができます。それに基づいて、賛成票を投じて回答を受け入れます(明確な「勝者」がいると仮定します)。

とにかく、クラス自体に:

getter/setter クラス メソッドについて多くの議論が見られますが、単純なプロパティ変数に直接アクセスする方がよいのでしょうか、それともすべてのクラスに明示的な get/set メソッドを定義する必要があるのでしょうか。後でロジックを追加する必要がある場合に備えて、明示的なメソッドを用意するというアイデアが気に入っています。その後、クラスを使用するコードを変更する必要はありません。ただし、次のような関数が何百万もあるのは嫌いです。

public function getFirstName()
{
   return $this->firstName;
}
public function setFirstName($firstName)
{
   return $this->firstName;
}

今、私はこれを行う最初の人ではないと確信しています (誰かが私に提案できるより良い方法があることを願っています)。

基本的に、PropertyHandler クラスには __call マジック メソッドがあります。"get" または "set" で始まる __call を経由するすべてのメソッドは、値を連想配列に設定または取得する関数にルーティングされます。配列のキーは、取得または設定後の呼び出しメソッドの名前です。したがって、__call に入るメソッドが「getFirstName」の場合、配列キーは「FirstName」です。

サブクラスにすでに「getFirstName」メソッドが定義されている場合に自動的に処理されるため、__call を使用するのが好きでした。私の印象 (間違っているかもしれません) は、__get & __set マジック メソッドはそれを行わないということです。

したがって、これがどのように機能するかの例を次に示します。

class PropTest extends PropertyHandler
{
    public function __construct()
    {
        parent::__construct();
    }
}

$props = new PropTest();

$props->setFirstName("Mark");
echo $props->getFirstName();

PropTest には実際には「setFirstName」または「getFirstName」メソッドがなく、PropertyHandler もないことに注意してください。配列の値を操作しているだけです。

もう 1 つのケースは、サブクラスが既に何か他のものを拡張している場合です。PHP では真の多重継承を行うことができないため、サブクラスに PropertyHandler インスタンスをプライベート変数として持たせることができます。もう 1 つ関数を追加する必要がありますが、その後はまったく同じように動作します。

class PropTest2
{
    private $props;

    public function __construct()
    {
        $this->props = new PropertyHandler();
    }

    public function __call($method, $arguments)
    {
        return $this->props->__call($method, $arguments);
    }
}

$props2 = new PropTest2();

$props2->setFirstName('Mark');
echo $props2->getFirstName();

サブクラスには、PropertyHandler __call メソッドにすべてを渡すだけの __call メソッドがあることに注意してください。


このように getter と setter を処理することに対するもう 1 つの良い議論は、文書化が非常に難しくなるということです。

実際、文書化されていない明示的なメソッドが存在しないため、どのような種類の文書生成ツールを使用することも基本的に不可能です。

私は今のところ、このアプローチをほとんど放棄しました。興味深い学習課題でしたが、明快さを犠牲にしすぎていると思います。

4

8 に答える 8

5

私がそれを行う方法は次のとおりです。

class test {
    protected $x='';
    protected $y='';

    function set_y ($y) {
        print "specific function set_y\n";
        $this->y = $y;
    }

    function __call($function , $args) {
        print "generic function $function\n";
        list ($name , $var ) = split ('_' , $function );
        if ($name == 'get' && isset($this->$var)) {
            return $this->$var;
        }
        if ($name == 'set' && isset($this->$var)) {
            $this->$var= $args[0];
            return;
        }
        trigger_error ("Fatal error: Call to undefined method test::$function()");
    }
}

$p = new test();
$p->set_x(20);
$p->set_y(30);
print $p->get_x();
print $p->get_y();

$p->set_z(40);

どちらが出力されますか(わかりやすくするために改行が追加されています)

generic function set_x
specific function set_y

generic function get_x
20
generic function get_y
30

generic function set_z
Notice: Fatal error: Call to undefined method set_z() in [...] on line 16
于 2008-08-28T13:06:47.823 に答える
3

@ブライアン

これに関する私の問題は、「後でロジックを追加」するには、ゲッター/セッターでアクセスされるすべてのプロパティに適用されるブランケット ロジックを追加するか、if または switch ステートメントを使用して、アクセスしているプロパティを評価して適用できるようにする必要があることです。特定のロジック。

それは完全に真実ではありません。私の最初の例を見てください:

class PropTest extends PropertyHandler
{
    public function __construct()
    {
        parent::__construct();
    }
}

$props = new PropTest();

$props->setFirstName("Mark");
echo $props->getFirstName();

FirstNames を検証するためのロジックを追加する必要があるとしましょう。サブクラスに setFirstName メソッドを追加するだけで、代わりにそのメソッドが自動的に使用されます。

class PropTest extends PropertyHandler
{
    public function __construct()
    {
        parent::__construct();
    }

    public function setFirstName($name)
    {
        if($name == 'Mark')
        {
            echo "I love you, Mark!";
        }
    }
}

暗黙のアクセサー メソッドに関しては、PHP の制限に満足していません。

私は完全に同意します。私はこれを処理する Python の方法が好きです (私の実装は不器用なぼったくりです)。

于 2008-08-28T14:14:57.893 に答える
2

はい、そうです、変数は手動で宣言する必要がありますが、セッターのタイプミスを恐れているので、その方が良いと思います

$props2->setFristName('Mark');

新しいプロパティ (FirstName ではなく FristName) が自動生成され、デバッグが難しくなります。

于 2008-08-28T13:14:11.800 に答える
1

@マーク

ただし、メソッドでさえメソッドの新しい宣言が必要であり、ロジックを追加できるようにメソッドに配置する利点がいくらか失われます。ロジックを追加するには、とにかくメソッドの昔ながらの宣言が必要になるためです。デフォルトの状態(検出/実行する点で印象的な場所)では、この手法は(PHPで)パブリックフィールドよりも利点がありません。フィールドへのアクセスを制限していますが、独自の制限を持たないアクセサー メソッドを介して白紙の状態を与えています。チェックされていない明示的なアクセサーがどの言語の public フィールドよりも優れていることを認識していませんが、間違っている場合は自由に修正してください。

于 2008-08-28T14:28:13.150 に答える
1

パブリック フィールドを使用するだけでなく、メソッドを使用することも好きですが、PHP のデフォルトの実装 (__get() および __set() を使用) またはカスタム実装に関する問題は、プロパティごとにゲッターとセッターを確立していないことです。基本。これに関する私の問題は、「後でロジックを追加」するには、ゲッター/セッターでアクセスされるすべてのプロパティに適用されるブランケット ロジックを追加するか、if または switch ステートメントを使用して、アクセスしているプロパティを評価して適用できるようにする必要があることです。特定のロジック。

私はあなたのソリューションが好きで、あなたに拍手を送ります.PHPが暗黙的なアクセサメソッドに関して持っている制限に満足していません.

于 2008-08-28T13:14:25.543 に答える
0

2セント入れずにはいられない…

私はこの邸宅http://gist.github.com/351387__getを使用して (doctrine が行う方法と同様)、クラスの外部でのみプロパティにアクセスします。そうすれば、巨大な関数や関数を作成したり、子クラスでandをオーバーライドしたりする代わりに、必要に応じて機能をオーバーライドできます。__set$obj->var__get__set__get__set

于 2010-04-17T15:01:05.213 に答える
0

私は常にこの問題を __call と同様に処理してきましたが、これは私のクラスの多くでボイラープレートコードとほぼ同じになります。ただし、コンパクトであり、リフレクション クラスを使用して、既に設定したプロパティのゲッター/セッターのみを追加します (新しいものは追加しません)。getter / setter を明示的に追加するだけで、より複雑な機能が追加されます。であると予想される

コードは次のようになります。

/**
* Handles default set and get calls
*/
public function __call($method, $params) {

    //did you call get or set
    if ( preg_match( "|^[gs]et([A-Z][\w]+)|", $method, $matches ) ) {

        //which var?
        $var = strtolower($matches[1]);

        $r = new ReflectionClass($this);
        $properties = $r->getdefaultProperties();

        //if it exists
        if ( array_key_exists($var,$properties) ) {
            //set
            if ( 's' == $method[0] ) {
                $this->$var = $params[0];
            }
            //get
            elseif ( 'g' == $method[0] ) {
                return $this->$var;
            }
        }
    }
}

これを、次のようなデフォルト プロパティを宣言したクラスに追加します。

class MyClass {
    public $myvar = null;
}

$test = new MyClass;
$test->setMyvar = "arapaho";

echo $test->getMyvar; //echos arapaho    

リフレクション クラスは、あなたが提案していたものに役立つものを追加する場合があります。きちんとしたソリューション @Mark。

于 2008-08-28T15:02:40.510 に答える
0

つい最近、あなたが提案した方法でゲッターとセッターを処理することも考えました (2 番目のアプローチ、つまりプライベート $props 配列が私のお気に入りでした) が、私のアプリではうまくいかなかったので破棄しました。

私はかなり大規模な SoapServer ベースのアプリケーションに取り組んでおり、PHP 5 の soap インターフェイスは、クラス内の既存または非存在のプロパティを気にすることなく、soap を介して直接送信される値を関連するクラスに挿入します。

于 2009-01-06T20:21:32.533 に答える