yujiro's blog

エンジニアリング全般の事書きます

【PHP】scalar_object を使って値からメソッドを使えるようにする。phpenv環境、Laravelで使えるようにした。

Ruby だと組み込み型を拡張してメソッド追加できるんだけど、PHPでもそんなことがしたかった。調べてみたら下記があった。

github.com

PHP の「文字列」や「配列」などの基本的な値型にメソッドを生やして使えるようにするという試み。

以下が手順です、phpenv に導入しました。

$ cd ~/.phpenv/src/

$ git clone https://github.com/nikic/scalar_objects.git

$ cd scalar_objects

$ phpize && ./configure && make && make install

$ vi ~/path/to/各バージョン/php.ini

+ extension=scalar_objects.so

終了。

早速試した。ちなみにphp7 です。

<?php

class ArrayExtension {

    public function specifiedNextKey($self, $key)
    {
        $tmp=false;
        foreach($self as $k => $v){
            if($k == $key){
              $tmp=$k;
            }elseif($tmp !== false){
              return $k;
            }
        }
        return false;
    }

    public function hoge($self)
    {
        var_dump($self);
    }

    public function getFirstKey($self){
      reset($self);
      return key($self);
    }

    public function sortArrayByKey($self, $sortKey, $sortType = SORT_ASC )
    {
        $tmpArray = [];
        foreach ( $self as $key => $row ) {
          $tmpArray[$key] = $row[$sortKey];
        }
        array_multisort( $tmpArray, $sortType, $self );
        return $self;
    }

}


register_primitive_type_handler('array', 'ArrayExtension');

$a = ['hello' => 'val1', 'fuga' => 'val2']->specifiedNextKey('hello');

var_dump($a);

$a = ['hello' => 'val', 'Hoge' => 'val2', 'aiueo' => 'val3']->getFirstKey();

var_dump($a);

$tajigen = [
    ['seiseki' => 50, 'syukketu' => 1],
    ['seiseki' => 30, 'syukketu' => 3],
    ['seiseki' => 20, 'syukketu' => 5],
    ['seiseki' => 10, 'syukketu' => 19],
    ['seiseki' => 70, 'syukketu' => 1],
];

$a = $tajigen->sortArrayByKey('syukketu');

var_dump($a);
/home/vagrant/php/scalar_objects/mytest.php:45:
string(4) "fuga"
/home/vagrant/php/scalar_objects/mytest.php:49:
string(5) "hello"
/home/vagrant/php/scalar_objects/mytest.php:61:
array(5) {
  [0] =>
  array(2) {
    'seiseki' =>
    int(50)
    'syukketu' =>
    int(1)
  }
  [1] =>
  array(2) {
    'seiseki' =>
    int(70)
    'syukketu' =>
    int(1)
  }
  [2] =>
  array(2) {
    'seiseki' =>
    int(30)
    'syukketu' =>
    int(3)
  }
  [3] =>
  array(2) {
    'seiseki' =>
    int(20)
    'syukketu' =>
    int(5)
  }
  [4] =>
  array(2) {
    'seiseki' =>
    int(10)
    'syukketu' =>
    int(19)
  }
}

いいね。。。

さっそくグローバル関数になってる関数を各値のメソッドに移植してみた。

Laravel 5 で使えるようにしたかったので、app のしたに Extensions ディレクトリを作って

<?php

namespace App\Extensions;

class StringExtension {

    public function mbTrim($self)
    {
        static $chars = "[\\x0-\x20\x7f\xc2\xa0\xe3\x80\x80]";
        return preg_replace("/\A{$chars}++|{$chars}++\z/u", '', $self);
    }

    public function removeHttpProto($self)
    {
        return preg_replace('/http[s]*:\/\/(.*?)\//', '', $self);
    }

    public function underscore($self)
    {
        return ltrim(strtolower(preg_replace('/[A-Z]/', '_\0', $self)) , '_');
    }

    public function camelize($self)
    {
        return lcfirst(strtr(ucwords(strtr($self, ['_' => ' '])) , [' ' => '']));
    }

}

を作った。

それで app/Providers/AppServiceProvider.php

    public function boot()
    {
        //
        register_primitive_type_handler('string', 'App\Extensions\StringExtension');
    }

とした。

Command を適当に作ってみて試してみる。

    public function handle()
    {
        //
        dd('HogeClass'->underscore()); 
    }
 

$ php artisan hogehoge

"hoge_class"

いい感じです。

参考

qiita.com