カテゴリーアーカイブ FuelPHP

著者:杉浦

【PHP】namespaceとautoloadの概要と連携

 最近、独自のオートローダを持つPHPプログラムを触ることになったので大雑把にnamespaceとautoloadの概要と連携を紹介します。
 namespace(名前空間)は1ファイルでも有効な変数名、関数名、クラス名等の区分け用の仕組みです。次の画像の様にちょっとしたスクリプトでも機能します。

 大雑把には各定義に接頭辞がついている様なものです。よくIDEのジャンプがnamespaceを元に働きますが、namespaceはファイルの読み込みに直接の関係を持ちません。
 autoloadは大まかには

public function autoload(string $呼び出す対象の名前){
    // なんやかんや処理
    require $呼び出す対象の書かれたファイルのパス;
    // あるいは
    include $呼び出す対象の書かれたファイルのパス;
}

PHP: require – Manual
PHP: include – Manual
をいい感じに動かす機能です。autoloaderによって多数のPHPソースコードファイルの中から必要な分だけPHPソースコードファイルを読み込みます。
 namespaceとautoloadのそれぞれは互いに関係ありません。PSR-4で定められた規約に従ってnamespaceとautoloadは連携します。
PSR-4 autoloader (日本語訳) – Qiita
PSR-4: Autoloader – PHP-FIG
 PSR-4はnamespaceとファイルの配置を定義づける規約です。大雑把にいえばnamespaceの名前、階層をディレクトリ構造と一致させなさい、という規約です。
 新しめのフレームワーク(laravelなど)やオートローダ(composerなど)はこのPSR-4に従っているためnamespaceによってファイル読み込みをしているとも言えます。ファイルを読み込めない時はコーディングをしている人が謎namespaceを定義してしまった時が大半です。逆にPSR-4に従っていない古いオートローダはnamespaceが通じているといってソースコードが読み込めているとは限りません。そういった場合、使われているオートローダのドキュメントなりソースコードなりを読み込む必要があります。
 

  • この記事いいね! (0)
著者:杉浦

【PHP】DI(依存性注入)を用いたコードの追い方

 DI(Dependency injection)(依存性注入)とはコード内で外部への依存を直書きするのでなく、外部から引数、セッターなどで依存する部分を与える実装のことです。例えば、次です。

use Illuminate\Contracts\Hashing\Hasher as HasherContract;

class DatabaseUserProvider implements UserProvider
{
    /**
     * The hasher implementation.
     *
     * @var \Illuminate\Contracts\Hashing\Hasher
     */
    protected $hasher;

    /**
     * Create a new database user provider.
     *
     * @param  \Illuminate\Contracts\Hashing\Hasher  $hasher
     * @return void
     */
    public function __construct(HasherContract $hasher)
    {
        $this->hasher = $hasher;
    }
    /**
     * Validate a user against the given credentials.
     *
     * @param  \Illuminate\Contracts\Auth\Authenticatable  $user
     * @param  array  $credentials
     * @return bool
     */
    public function validateCredentials(UserContract $user, array $credentials)
    {
        return $this->hasher->check(
            $credentials['password'], $user->getAuthPassword()
        );
    }
}

 DatabaseUserProviderクラスがインスタンス化された際にHasherContract型の引数$hasherを要求し、$hasherを保持します。保持した$hasherをvalidateCredentialsメソッド内で用います。
 外部から依存するモノを与えるため、テストし易かったり変更し易かったりするのですが、あまりに自由で今稼働しているコードでは何が実体化しているのかわかりにくく、追うのが少し難しいです。上記コードなら$this->hasherって何?となってIDEの機能で型を追ってもHasherContractというインターフェースが現れて終わりです。HasherContractを満たすどのHasherクラスが使われているか分かりません。
 hasherの中身、ひいては実際の動作を知りたい時は、まず依存性が実際に注入された際のコードを動かし、その時のhasherの中身に何が入ってるのか調べる必要があります。PHPならば次の様に出来ます。

    public function __construct(HasherContract $hasher)
    {
        var_dump(get_class($hasher));exit;
        $this->hasher = $hasher;
    }

PHP: get_class – Manual
 get_class関数でインスタンスそのものに、あなたのクラス名は何ですか、と尋ねます。得られたクラス名が今稼働しているシステムで注入されているクラスの名前です。例えば、ここでBcryptHasherという実装クラスが呼ばれているとわかったら次の様に型付けをします。

class DatabaseUserProvider implements UserProvider
{
    /**
     * The hasher implementation.
     *
     * @var \Illuminate\Hashing\BcryptHasher
     */
    protected $hasher;

    /**
     * Create a new database user provider.
     *
     * @param  \Illuminate\Hashing\BcryptHasher  $hasher
     * @return void
     */
    public function __construct(BcryptHasher $hasher)
    {
        $this->hasher = $hasher;
    }
    /**
     * Validate a user against the given credentials.
     *
     * @param  \Illuminate\Contracts\Auth\Authenticatable  $user
     * @param  array  $credentials
     * @return bool
     */
    public function validateCredentials(UserContract $user, array $credentials)
    {
        return $this->hasher->check(
            $credentials['password'], $user->getAuthPassword()
        );
    }
}

 こうするとIDEのジャンプ機能はインターフェースHasherContractでなくクラスBcryptHasherを参照するようになり、静的にコードを追うことが格段に楽になります。注意点として直し忘れがあります。DIを駆使したコードほど直し忘れると型エラーで派手に事故ります。

  • この記事いいね! (1)
takahashi 著者:takahashi

FuelPHPで今開いているページのコントローラー/アクションを取得する方法

・コントローラー名を取得したいとき(コントローラークラス名)

echo Request::main()->controller;
//ex.: Controller_Hogehoge

・アクション名を取得したいとき

echo Request::active()->action:
//ex.: huga

なお、コントローラーを取る方法として、Uriクラスを使って

 echo Request::main()->uri->segment(1);  //ベースURLから1番目の値をとる

とすることもできるようですが、index(/)などの場合、取得できる値がNULLになってしまう問題があるため、個人的には最初の方法で取得したうえで正規表現などで加工した方が確実かな、と思います。

参考:
[PHP][FuelPHP]FuelPHPで気になるあの情報の取り出し方 – ECサイト運営開発記

  • この記事いいね! (0)