php5.4の新機能(Trait)

前回、Traitsについて書くと書きましたが、
それについて自分がしっかり理解できていなかったのですね、、、、

Traitsのサンプルをみると

trait A {
  public function smallTalk() {
    echo 'a';
  }

  public function bigTalk() {
    echo 'A';
  }

}

trait B {
  public function smallTalk() {
    echo 'b';
  }

  public function bigTalk() {
    echo 'B';
 }

}

 class Talker {
   use A, B {
     B::smallTalk instead A;
     A::bigTalk instead B;
   }
 }

$talker = new Talker();
$talker->smallTalk(); //bと表示
$talker->bigTalk(); //Aと表示

みたいな例が出てきますが、これって

class A {
  public function smallTalk() {
    echo 'a';
  }
  public function bigTalk() {
    echo 'A';
  }
}

class B {
  public function smallTalk() {
    echo 'b';
  }
  public function bigTalk() {
    echo 'B';
  }
}

class Talker {

  private $a;
  private $b;

  public function __construct() {
    $this->a = new A();
    $this->b = new B();
  }

  public function smallTalk() {
    $this->b->smallTalk();
  }

  public function bigTalk() {
    $this->a->bigTalk();
  }

}

$taker = new Talker();
$talker->smallTalk(); //bと表示
$talker->bigTalk(); //Aと表示

と変わらないんじゃねーの? と思ってたのです。
しかし、ここのサンプルをみて、Traitの意味が分かってきたのです!
https://wiki.php.net/rfc/traits

class Base {
  public function sayHello() {
    echo 'Hello ';
  }

}

trait SayWorld {
  public function sayHello() {
    parent::sayHello(); //親クラスが無いのにpearent?
    echo 'World!';
  }
}

class MyHelloWorld extends Base {
  use SayWorld;
}

$o = new MyHelloWorld();
$o->sayHello(); // Hello World! と表示される

なるほど、これは他のクラスへのデリゲーションでは実現できない。

  • 継承はコードの再利用ができるけど、親クラスは一つのみ(ダイアモンド継承を避けるため)
  • デリーゲーションは、制約なく色々組み合わせる事が出けど、継承関係の再組み合わせは出来ない。

この問題を解決するための新しい単位が「Trait」か!

上記の例は、正直使いどころが直ぐに思い浮かばないけど、
下の例は結構便利そうですね。

trait Hello {
  public function sayHelloWorld() {
    echo 'Hello'.$this->getWorld();
  }

  abstract public function getWorld(); //実装を呼び出し側に任せる
}

class MyHelloWorld {
  private $world;
  use Hello;

  public function getWorld() {
    return $this->world;
  }

  public function setWorld($val) {
    $this->world = $val;
  }
}

上の例も、デリゲーションでもなんとかなるけど、abstractという形で実装の強制はできないし、
なによりデリゲーションよりずっとコード量がへるので便利ですね!

php5.4の新機能を2週にわたってレビューしましたが、いかがでしょうか?
他にこんな新機能も注目だよ!っていうのがあれば教えて下さい。

php5.4の新機能

php5.4αが7/5にリリースされましたが、
そのなかで気になった機能を紹介したいとおもいます。

1. 配列をメソッドチェーンのように参照可能

php5からおなじみのメソッドチェーンですが、

class A
{
  public function foo() {
    return new B();
  }
}

class B
{
  public function bar() {
    return "あっちゃん";
  }
}

$a = new A();
echo $a->foo()->bar(); //「あっちゃん」と表示される。

戻り値を配列にした時は1度変数に入れないと、インデックスにアクセスすることは出来ませんでした。

class A
{
  public function foo() {
    return array('name' => 'あっちゃん');
  }
}

$a = new A();
$foo = $a->foo();
echo $foo['name'];

php5.4からはメソッドチェーンのように配列のインデックスにアクセス可能です。

$a = new A();
echo $a->foo()['name']; //「あっちゃん」と表示される。

2. callable配列をそのまま実行可能

callable配列( array(‘class’, ‘method’) )をそのまま実行出来るようになりました。

class Foo
{
  public function bar($name) {
    echo "こんにちは, $name";
  }
}

$f = array('Foo','bar');
echo $f('まりこさま'); // 「こんにちは, まりこさま」と表示される。

詳しくはこちらを御覧ください。

3. クロージャの中で$thisが使える

クロージャでの$thisの呼び出しがサポートされました。

class A
{
  private $value = 'ともちん';
  function single_getter($name) {
    return function() use ($name) {
      return $this->$name;
    };
  }
}
class B
{
  private $value = 2;
  function test() {
    $a = new A;
    $private_getter = $a->single_getter('value');
    print $private_getter();
  }
}

$b = new B;
$b->test();

php5.3までは、 「Fatal error: Using $this when not in object context」でしたが
php5.4では、「ともちん」と表示されます。

4.Traitsのサポート

でました、Traits。
この説明だけで一つ記事が出来ると思うので、次回書かせていただきます。

4.Traitsのサポート

でました、Traits。
この説明だけで一つ記事が出来ると思うので、次回書かせていただきます。