c4se記:さっちゃんですよ☆

.。oO(さっちゃんですよヾ(〃l _ l)ノ゙☆)

.。oO(此のblogは、主に音樂考察Programming に分類されますよ。ヾ(〃l _ l)ノ゙♬♪♡)

音樂は SoundCloud に公開中です。

考察は現在は主に Scrapbox で公表中です。

Programming は GitHub で開發中です。

PHP でRay.DiとRay.Aopをやってみる

追記 2014-12-19
Ray.Di, Ray.Aopを参考に、より簡単なinterfaceのDI/AOPライブラリを実装しました。お使ひください。
cf. PHPで簡単に華麗にDIとAOPをキメる http://c4se.hatenablog.com/entry/2014/12/11/013136

PHP Advent Calendar 2013 19日目です。みなさまに於かれましてはネコと和解されましたでせうか。昨日はPHP 文字列リテラルにおける変数展開ノ全テ - do_akiの徒然想記でした。うげ、複雑な構文2って然ふだったのか。securityとしては洞うなの……。


PHPの開発にGrunt使へ、と云ふ話しを予定してゐたのですが、ADVENTARの方のPHP Advent Calendar 2013PHP 開発でも Grunt を使う - ngの日記に書かれてしまひました。因みにわたしのGruntfile.jsは、

'use strict';

module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    exec: {
      fixer: {
        command: 'php php-cs-fixer.phar fix lib/ --level=all',
        stdout: true,
        stderr: true
      },
      lint: {
        command: 'find *.php -exec php -l {} \\; && ' +
                 'find templates/ -name \\*.php -exec php -l {} \\; && ' +
                 'find lib/ -name \\*.php -exec php -l {} \\;',
        stdout: true,
        stderr: true
      }
    },
    jshint: {
      options: {jshintrc: '.jshintrc'},
      all: [
        'Gruntfile.js'
      ]
    }
  });

  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-exec');

  grunt.registerTask('test', ['jshint', 'exec:lint', 'exec:fixer']);
};

です。lintとfixerをgrunt-execで回してゐます。Windowsではfind commandが動きません。
と云ふかどうせbowerとか使ふのだから、node.jsは必須です。Gruntを使ふと便利です。わたしは平気でGruntfile.jsからrakeを呼んだりしますが。

PHPの闇

いきあたりバタリ感のすごいPHPの仕様 (特に標準関数) ですが、最近はだいぶんPHPの闇も晴れてきました。しかしPHP教育の闇は相変わらずです。
PSR (Proposing a Standards Recommendation)は闇を晴らす光です。PSRの無いPHPを教えるな。Composer http://getcomposer.org https://packagist.org で依存関係の管理や適用が随分楽に成りました。PSR-0 (Autoloading Standard) と PSR-4 (Autoloader) に従いrequireをComposerに任せれば (ComposerはPSR-0 autoloaderも内蔵してゐ、localで使へます) 、よいclass構造を保つ助けに成ります。PSR-1 (Basic Coding Standard) と PSR-2 (Coding Style Guide) はcoding styleですから異論は有るでせうが、理由が無ければ採用すべきです (採用しない場合は理由を文書で記述するべきです)。PSR-3 (Logger Interface) が有るので便利なMonolog https://github.com/Seldaek/monolog を心配せずに使へます。Web siteにloggingは必須ですね?
此等はdefacto standardですが、技術に於いて標準はdefacto standard以外に有り得ません。標準に違反する場合、明示的に違反するべきです。殴り返して貰う為に殴るべきです。

Ray.DiとRay.Aopを触ってみる

さて、前述は前置きで、Ray.DiとRay.Aopを触ってみます。
cf. BEAR.Resource ≪ BEAR Blog http://www.bear-project.net/blog/2012/04/bear-resource/
cf. Object Framework - Ray.Di ≪ BEAR Blog http://www.bear-project.net/blog/2012/04/di/
cf. Object Framework - Ray.Aop ≪ BEAR Blog http://www.bear-project.net/blog/2012/04/object-framework-ray-aop/
cf. Ray.Di / Ray.Aop コトハジメ // Speaker Deck https://speakerdeck.com/madapaja/ray-dot-aop-kotohazime
cf. Ray.Di-Ray.AopからみるPHP5.4+フレームワークBEAR.Sunday // Speaker Deck https://speakerdeck.com/madapaja/ray-dot-di-ray-dot-aopkaramiruphp5-dot-4-plus-huremuwakubear-dot-sunday
BEAR.Sunday http://bearsunday.github.io/ のものですが、あわよくばせしめてやらう、と云ふ魂胆です。
Composerを落として、./composer.phar initする。

{
    "name": "vagrant/ray",
    "description": "Ray test.",
    "require": {
        "ray/di": "dev-develop",
        "ray/aop": "dev-develop"
    },
    "license": "Public Domain",
    "authors": [
        {
            "name": "Sachirou Inoue",
            "email": "utakata.c4se@gmail.com"
        }
    ]
}

(因みに何かする時は直ぐVMを作ります。vagrant upで作ってvagrant destroyで消せば好い丈です。)

Ray.Di

Ruby使ってるとinstance_evalしたりしますが、PHPは存外静的で、DI (Dependency Injection) が有ると助かります。Pimpleも好く使ひますが、阿れはただのコンテナで、少し力不足な事があります。
cf. Pimple - A simple Dependency Injection Container for PHP 5.3 http://pimple.sensiolabs.org/
cf. koriym/Ray.Di https://github.com/koriym/Ray.Di
cf. PHP5.4+フレームワーク BEAR.Sundayを理解するためにRay.Diを触ってみるの巻 其の弐 : 今日も適当ダイアリー http://blog.madapaja.net/2012/07/php54-bearsundayraydi_11.html

Injectionだけする例。

<?php
$loader = require __dir__ . '/vendor/autoload.php';

use Doctrine\Common\Annotations\AnnotationRegistry;
use Ray\Di\Di\Inject;
use Ray\Di\Di\Named;
use Ray\Di\AbstractModule;
use Ray\Di\Injector;

class RModel
{
    private $obj;

    /**
     * @Inject
     * @Named("obj=obj_sample")
     */
    public function __construct(\RObj $obj)
    {
        $this->obj = $obj;
    }

    public function lookin()
    {
        var_dump($this->obj);
    }
}

class RObj
{
}

class RModule extends AbstractModule
{
    public function configure()
    {
        $obj = new RObj;
        $this->bind('RObj')->annotatedWith('obj_sample')->toInstance($obj);
    }
}

AnnotationRegistry::registerLoader([$loader, 'loadClass']);
$injector = Injector::create([new RModule]);
$model = $injector->getInstance('RModel');
$model->lookin();

RObjをRModelにinjectします。Injector::create([new RModule])でRModuleのconfigureが実行され、$injector->getInstance('RModel')でinjectします。
次はinterfaceでやるね……。
然ふ云へば此の引数名でinjectするやつ、AngularJSのinjectionで最近見たな……。AngularJSと言へばAngularDartも出ましたね。Dartって何が嬉しいの。

Ray.Aop

まあRubyはclass書き換えるの簡単ですし、今ならModule#prependもできましたから余りAOP (Aspect Oriented Programming) する事はありませんが、AspectRを一度だけ使った事が有ります。なんでだったかな……。まぁAspectRは、methodの上書きと余り変わらない事をやってゐるし (実際はもっとdirtyで文字列evalしてる)。
cf. Module: AspectR http://www.ruby-doc.org/gems/docs/a/aspectr-0.3.7/AspectR.html
cf. koriym/Ray.Aop https://github.com/koriym/Ray.Aop

Aspect追加のみする例。Ray.Diを使った。

<?php
$loader = require __dir__ . '/vendor/autoload.php';

use Doctrine\Common\Annotations\AnnotationRegistry;
use Ray\Di\AbstractModule;
use Ray\Di\Injector;
use Ray\Aop\MethodInterceptor;
use Ray\Aop\MethodInvocation;

class RModel
{
    public function command()
    {
        echo "Method body.\n";
    }
}

class RIntercepter implements MethodInterceptor
{
    public function invoke(MethodInvocation $invocation)
    {
        echo "Aspect before.\n";
        $result = $invocation->proceed();
        echo "Aspect after.\n";

        return $result;
    }
}

class RModule extends AbstractModule
{
    public function configure()
    {
        $this->bindInterceptor(
            $this->matcher->any(),
            $this->matcher->any(),
            [new RIntercepter]);
    }
}

AnnotationRegistry::registerLoader([$loader, 'loadClass']);
$injector = Injector::create([new RModule]);
$model = $injector->getInstance('RModel');
$model->command();

RModuleで指定されたclassの全てのmethodにRIntercepterを被せる様指定し、$injector->getInstance('RModel')でRModelに適用してゐる。
DIとAOPとの関係は、直感的には解ってゐない。余りに使い慣れないからだ。JavaScriptではSingletonは標準的な存在だからな……。


明日は @ さんです。