名前空間付き函数 VS 静的メソッド ﾌｧｲｯ

名前空間を活用した[【PHP超入門】名前空間（namespace・use）について](http://qiita.com/7968/items/1e5c61128fa495358c1f)が網羅的で良かったので、ふだんから考へてることをまとめたポエムです。**結論はないです。**

## はじめに

オブジェクト指向的な設計の観点からはユーティリティクラス(静的メソッドのみを持つクラス)は、均衡を崩すものとして忌み嫌はれる存在であることは意識しておいた方が良いです。[関数とユーティリティクラスは禁止 - 株式会社アークシステム(infoARK)](http://www.arksystems.co.jp/closeupit/object_oriented/0401.html)のような議論についてはしっかりと咀嚼する価値があります。

…………が、そんな高尚な設計の話をしたり設計の批判をするのは簡単ですが現実世界では動くコードが正義です。オブジェクト指向の大先生にならなきゃプログラムを書いちゃいけないなんてことは断じてありません。あなたの目的を達成するためにプログラミング言語は存在するのだから、利用できる機能はなんでも利用しませう。

そんなわけで、この記事では大手を振って函数とユーティリティクラスの礼賛をします。それと記事の題名について最初に個人的な見解を伸べると、私は**静的メソッドを利用することの方が比較的多い**です。

## 名前空間について

はじめにPHPマニュアルの[名前空間](http://php.net/manual/ja/language.namespaces.php)をひととほり読むことをおすすめします。読みましたね？

## 函数呼び出しっぽいものの分類

函数とかメソッドとかいろいろあるので、呼び出しの書式ごとに分類を整理します。一般的にはクラスに属しないものを「函数」、クラスに属するものを「メソッド」と呼びます。でもPHPで定義するための文法上のキーワードはメソッドふくめてぜんぶ`function`です。 *へんなの。*

| コード            | 説明 |
|-----------------|-----|
| `hoge()`        | 自身と同じ名前空間*(なければトップレベル名前空間)*の`hoge`函数 |
| `\fuga()`       | トップレベル名前空間の`fuga`函数 |
| `foo\bar\buz()` | `foo\bar`名前空間に属する`buz`函数 |
| `$obj->cool()`  | インスタンスオブジェクト`$obj`の`cool`メソッド |
| `foo\Bar::hot`  | `foo`名前空間に属する`Bar`クラスの`hot`静的メソッド |
| `$piyo()`       | [callable](http://php.net/manual/ja/language.types.callable.php)なローカル変数 `$piyo` の呼び出し |

callableな値`$piyo`の実態は[無名関数](http://php.net/manual/ja/functions.anonymous.php)だったり、配列だったり、文字列だったりします。詳しくは[可変関数](http://php.net/manual/ja/functions.variable-functions.php)を呼んでください。

```php
$piyo = 'hoge'; // hoge() と同じ
$piyo = '\fuga'; // \fuga() と同じ
$piyo = 'foo\bar\buz' // foo\bar\buz() と同じ
$piyo = [$obj, "cool"]; // $obj->cool() と同じ
$piyo = ['foo\Bar', 'hot']; // foo\Bar::hot() と同じ
$piyo = function () use ($v) { ... }; //無名函数(クロージャ)
```

## 名前空間付き函数について

[【PHP超入門】名前空間（namespace・use）について](http://qiita.com/7968/items/1e5c61128fa495358c1f)に概ね網羅されてますので、よくお読みください。

## クラスの静的メソッド

**静的メソッド**とは、インスタンス化(`$obj = new HogeClass`)しなくても利用できるメソッドのことです。

```php
final class HogeUtil
{
    /**
     * "foo"を$n回繰り返した文字列を返す
     *
     * @param  int    $n
     * @return string
     */
    public static function foo($n)
    {
        return str_repeat("foo", $n);
    }
}
```

一切インスタンス化させずに静的メソッドを利用するために用意するクラスのことを「ユーティリティクラス」と呼びます。

## オートローディング

ところで、PHPには[クラスのオートローディング](http://php.net/manual/ja/language.oop5.autoload.php)と呼ばれる仕組みがあります。モダンなPHPでは、いちいちファイルごとに`include_once`とか`require_once`と書かずに読み込む方法がベストプラクティスとされてます。

[モダンPHPアンチパターン #ファイルごとにrequire/includeを書く](http://qiita.com/tadsan/items/157969b338fd8b782b21#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%94%E3%81%A8%E3%81%ABrequireinclude%E3%82%92%E6%9B%B8%E3%81%8F)とかにちょろっと書いたんですが、基本はComposerをちゃんと設定すれば、それだけでクラスを自動ロード化することができます。 <small>(ちょっと小声でステマをさせていただくと、[WEB+DB PRESS Vol.91](http://gihyo.jp/magazine/wdpress/archive/2016/vol91)に名前空間とクラスについてしっかりと説明した記事を書いたので、よろしければ買って読んでね！)</small>

### オートローディングの限界

さて、クラスは自動ロードできるのですが、名前空間に直接定義された函数はできません。事前に全て読み込んでおくか、必要に応じて`include_once`または`require_once`させるしかありません。

名前空間付き函数をComposerのライブラリとして提供するには、`composer.json`的には`{"autoload": {"files": ["src/functions.php"]}}`のような定義で事前に読み込んでおくことになります。

ちなみに私がふだん仕事で携ってるプロジェクトの共通ロジック部分には1286クラス、7421メソッドありました。こんなの全部を事前ロードはあんまりやりたくない。

## grepの敗北

`use`を利用すると長い名前空間・クラス名・函数名を省略することが簡単にでき、とてもべんりです… 便利ですが、たとへば函数の名前を変更しようと思ったとき、あるいは引数の仕様を変更しようと思ったときに`use`を使ってると少々厄介なことになります。

人間、数多くのコードを書いたり息を吸ったり吐いたりしてると、この「メソッドいまいちだったな」なんて気分になることは割とよくあります。名前空間なしのクラスの静的メソッド`Hoge::fuga()`のメソッドをリネームするのは簡単です。`grep`などのテキスト検索ツールで`grep -r Hoge::fuga( .`なんて検索してやれば利用箇所を洗い出して置換していくことができます。極端な話、`sed`でリファクタリングができます。

世のなかには[PHP-Parser](https://github.com/nikic/PHP-Parser)のようなライブラリも多くあるので、こういったものをうまく組み合せればもっとうまくリファクタリングができるはずなんですが…

### 静的メソッドの良くないところと対処

バッドノウハウです。わかってやってます(断言)

* 継承したクラスから呼び出すことができる
    * 継承されると、単純にgrepできない
    * → **ユーティリティクラスを`final class Hoge`のように定義すれば継承されないことを保証できる**
* インスタンス化して呼び出すことができる
    * 静的メソッドとして定義しても`$obj->fuga()`として呼び出すことが可能
    * → **コンストラクタを`private function __construct()`で定義してインスタンス化を封じる**

## traitってどうなの?

[トレイト](http://php.net/manual/ja/language.oop5.traits.php)(`trait`)はPHP 5.4で導入された仕組みで、継承とは別の軸でクラスに機能を組込むことが可能です。拙作の[BaguettePHP/objectsystem](https://github.com/BaguettePHP/Objectsystem)は`trait`を活用してオブジェクトを機能的に拡張することができます[^1]。


さて、実は`trait`に定義した静的メソッドは継承しなくても呼び出すことができます。またクラスに`use`して利用できるようになるので、Rubyの[Math](https://docs.ruby-lang.org/ja/latest/class/Math.html)モジュールを`include`するような使用感[^2]になって良いのではないか、と**期待したのですが……**。`use`しちゃったら`grep`がめんどくさくなる問題は何も解決しないので私はやめました。

`trait`はうまく利用すれば効果的で素晴しい機能なのですが、下手な作りにすると非常にコードが追ひにくくなって「ユーティリティクラスにした方がはるかに読みやすい」事態にも容易になりえるので、現実とはままならないものです。

-------

## 特に落ちはなく結び

世の中のPHPerはどうやってリファクタリングを断行してるんだろう… ちゃんと静的解析できればリネームに限らずスマートにリファクタリングできるはずなんだけど、手元のツールできちんとそれが実現できそうなのはPhpStormしかなかった。

水は低きに流れる。みんな`grep`が好きなので静的メソッドに流れる。あんまり健康な状態じゃないのでテクノロジーで反抗して勝利していきたい。

## 裏技

[AspectMock](https://github.com/Codeception/AspectMock)と名前空間を
悪用
活用すると、PHPの標準函数をモック化できるぞ！ たぶん！

## 脚注

[^1]: [private/protectedなプロパティを外部から読み込み可能にする - Qiita](http://qiita.com/tadsan/items/2049243e47495764b191)とか[インスパイヤされて掲示板を作りたくなった(3) - Qiita](http://qiita.com/tadsan/items/498710c5199349e6d7a8)あたりで利用方法を解説してます ヾ(〃＞＜)ﾉﾞ
[^2]: ちなみにRubyの`Math`メソッドのような仕様の