PHPを愛する試み 〜調教編〜

PHPを愛する試みというのを個人的にやっている。

最近仕事でPHPをガリガリ使わなければならない状況になってしまった。そのため可及的速やかにPHPを愛する必要がある。

tap

ときに、Rubyにはtapという素敵なメソッドがある。

tapかわいいよtap

PHPでも$obj->tap(...)みたいに書きたい!

p

ときに、Rubyにはpという素敵なメソッドがある。

p (Kernel)

PHPでも$obj->p()みたいに書きたい!

ということで

今回はPHPを無理矢理Rubyっぽく使うという調教プレイでたわむれることにした。

どうやるか

ざっと調べたところ、

・どんなオブジェクトでもtapとpを使いたい。
・けどPHPにはRubyのように基底クラスを簡単に書き換えるような仕組みはなさそう
・かといって全てのクラスにメソッド実装するのはダルイ
C言語で拡張とか僕には無理だお

という感じだった。しかし、さらに調べるとrubyactivesupportっぽいことをPHPでやってる洋モノの変態さんを発見した。

ActiveSupport for PHP - Ruby style

なんかよさそう。ということで、ここから発想を得て以下のような仕組みを考えてみた。

・任意のオブジェクト$objをruby()に食わせると、->tap()と->p()が使えるようになる
・->tap()と->p()はメソッドチェインで->tap()->p()のように繋げることができる
ruby()に食わせたオブジェクトは->php()で元のオブジェクトに戻せる

Rubyっぽいメソッドを叩き込むドSファイル

ruby.php

<?php
class Ruby
{
    public function __construct($origin) {
        $this->origin = $origin;
    }

    public function tap($callback) {
        $callback($this->origin);
        return $this;
    }

    public function p() {
        var_dump($this->origin);
        return $this;
    }

    public function php() {
        return $this->origin;
    }
}

function ruby($origin) {
    return new Ruby($origin);
}

使ってみる

rubynize.php

<?php                                                                                                                                                             
require 'ruby.php';

class C
{
    public function __construct() {
        $this->name = 'hoge';
    }   
}

// オブジェクトをvar_dump
$c = new C();
ruby($c)->p();

// オブジェクトのnameプロパティにfugeをセット
$c = new C();
ruby($c)->tap(function ($x) {$x->name = 'fuge';});                                                                                                            
var_dump($c);

// オブジェクトのnameプロパティにfugeをセットし、オブジェクトをvar_dump
$c = new C();
ruby($c)->tap(function ($x) {$x->name = 'fuge';})->p();

// 上記の返り値をRubynizeする前のものにする
$c = new C();
$new_c = ruby($c)->tap(function ($x) {$x->name = 'fuge';})->p()->php();
var_dump($new_c);

チェイン(鎖)ー!

さらに使ってみる

rubynize2.php

<?php
require 'ruby.php';
 
class C
{
  public function setName($name) {
    $this->name = $name;
    return $this;
  }
 
  public function setSex($sex) {
    $this->sex = $sex;
    return $this;
  }
}
 
 
// 普通のメソッドチェイン
$c = new C();
$c->setName('hoge')->setSex('man');
var_dump($c);
 
// tapでnameをhoge->fugeに
$c = new C();
ruby($c->setName('hoge'))
  ->tap(function ($x) {$x->name = 'fuge';})
  ->php()
  ->setSex('man');
var_dump($c);
 
// tapでnameをhoge->fugeに。sexをman->womanに。さらにチェーンでvar_dump
$c = new C();
ruby(
  ruby(
    ruby($c->setName('hoge'))
    ->tap(function ($x) {$x->name = 'fuge';})
    ->php()
    ->setSex('man')
  )   
  ->tap(function ($x) {$x->sex = 'woman';})
)->p();

チェインチェイン(鎖鎖)ー!

終わり

ruby()が必要だったり->php()しなきゃだったりで、もっとすっきり出来そう。
だけど自分の能力ではこの辺が限界だお...
もっとPHPのことを知らなきゃですな...

※ 個人的にPHPとたわむれる試みなので、実用性とか(ry

※シリーズもので頑張ってる
PHPを愛する試み
PHPを愛する試み 〜調教編〜
PHPを愛する試み 〜self:: parent:: static:: および遅延静的束縛〜