LoginSignup
11
11

More than 5 years have passed since last update.

遅延静的束縛はアノテーションでも使える!PhpStorm での開発を助けるひと工夫

Last updated at Posted at 2014-01-14

主に PhpStorm7 で開発してらっしゃる方が対象です。
ほかの IDE では試していませんが、可能性はあるかもしれません。

ここでの「アノテーション」は、ドキュメントコメントで IDE にメタ情報を提供するための注釈を指しています。Web Application Framework への情報提供ではありません。
また、PSR に準拠しているか否かについては確認しておりませんのでご了承ください。

遅延静的束縛の static はアノテーションでも使える

たとえば、DB からとある Model(Entity) を取得する共通メソッドが親クラスで定義されていたとします。

Model.php
class Model {

    /*
     * モデル取得メソッド
     *
     * @param array|string|integer $parameters
     * @return Model
     */
    public static function findFirst($parameters=null) { }
}

これを継承して具象クラスを定義すると...

non-static.png

基底クラスで定義されている findFirst の戻り値は Model なので、最後の一文 $entry->dateModel にプロパティ $date が定義されていない旨の警告が表示されます。
(実際には magic method としてアクセスされるよというメッセージです)

つまり、 $entryEntry クラスのインスタンスとして扱いたい場面なのに、 Model クラスのインスタンスとして認識されてしまう、ということです。

そこで、 Model::findFirst のアノテーションを次のように修正します。

Model.php
class Model {

    /*
     * モデル取得メソッド
     *
     * @param array|string|integer $parameters
     * @return static
     */
    public static function findFirst($parameters=null) { }
}

@return に続く型注釈を Model ではなく static に変更しました。

static.png

これで警告は解除され、呼び出し元である Entry クラスのインスタンスとして認識されました。

例ではクラスのフィールドを参照しましたが、例えばせっかくメソッドチェーンを繋げられるように setter メソッドで $this を返却していても、具象クラスのインスタンスとして認識されなければ警告だらけになるわ入力補完が効かないわで残念な気持ちになりますよね。
返却されるインスタンスが具象クラスのものとなることがわかっている場合、アノテーションに static を指定するとそんなこともなくなります。

遅延静的束縛(static) について詳しいことは 公式マニュアル:遅延静的束縛 をご参照ください。

Phalcon でのお話

PhpStorm + Phalcon で開発されている方はもうお気づきかとは思いますが、上記の例をそのまま Phalcon の ドキュメントライブラリ に当てはめることで開発を加速できます。

ide/1.2.5/Phalcon/Mvc/Model.php#L388

Phalcon/Mvc/Model.php一部抜粋
<?php 

namespace Phalcon\Mvc {

    abstract class Model implements \Phalcon\Mvc\ModelInterface, \Phalcon\Mvc\Model\ResultInterface, \Phalcon\DI\InjectionAwareInterface, \Serializable {

        /* 省略 */

        /**
         * Allows to query a set of records that match the specified conditions
         *
         * <code>
         *
         * //How many robots are there?
         * $robots = Robots::find();
         * echo "There are ", count($robots), "\n";
         *
         * //How many mechanical robots are there?
         * $robots = Robots::find("type='mechanical'");
         * echo "There are ", count($robots), "\n";
         *
         * //Get and print virtual robots ordered by name
         * $robots = Robots::find(array("type='virtual'", "order" => "name"));
         * foreach ($robots as $robot) {
         *     echo $robot->name, "\n";
         * }
         *
         * //Get first 100 virtual robots ordered by name
         * $robots = Robots::find(array("type='virtual'", "order" => "name", "limit" => 100));
         * foreach ($robots as $robot) {
         *     echo $robot->name, "\n";
         * }
         * </code>
         *
         * @param array|string $parameters
         *              ...配列だけじゃなく文字列も渡せるので修正
         * @return \Phalcon\Mvc\Model\ResultsetInterface|static[]
         *              ...static[] を追加して具象クラスの配列として認識させる
         */
        public static function find($parameters=null){ }


        /**
         * Allows to query the first record that match the specified conditions
         *
         * <code>
         *
         * //What's the first robot in robots table?
         * $robot = Robots::findFirst();
         * echo "The robot name is ", $robot->name;
         *
         * //What's the first mechanical robot in robots table?
         * $robot = Robots::findFirst("type='mechanical'");
         * echo "The first mechanical robot name is ", $robot->name;
         *
         * //Get first virtual robot ordered by name
         * $robot = Robots::findFirst(array("type='virtual'", "order" => "name"));
         * echo "The first virtual robot name is ", $robot->name;
         *
         * </code>
         *
         * @param array|string|integer $parameters
         *              ...文字列も、実は数値(主キー値)も渡せる
         * @return static
         *              ...こちらも同様に具象クラスのインスタンスとして認識させる
         */
        public static function findFirst($parameters=null){ }


        /* 省略 */

    }
}

上記のように、アノテーションを4行書き換えます。
これに気づくまでは具象クラス側で find findFirst をオーバライドしてアノテーションを振り当てていましたが、これでその必要もなくなりました!

ふと Pull Request を送ろうかとも思ったのですが、Phalcon 全体としてのコーディングスタイルや PSR との衝突も考えられるので、あくまで個人的に調整する範囲であると考えこちらに投稿いたしました。

11
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
11