複数のファイルに全く同じメソッドを発見してしまいキレたの巻。
メソッドごとに切り出してそれが同じものであればコピペしやがったなこのやろうしけいだ!ってできるかな、と思った。まあ昨日の流れでphpcpdとかでチェックする話なのだろうけど、いざチェックしたとして、それを関数レベルでリファクタリングしていくのに有用ではないか、と感じたわけです。
とりあえず分解対象のクラスを作る。
<?php class Sample { public function __construct() { echo "__construct"; } private function privateFunction($param1) { echo "privateFunction"; } public function publicFunction($param1) { echo "publicFunction"; } /** * staticなFunctionです */ public static function staticFunction($param1, $param2 = 10) { echo "staticFunction"; } }
下記のコードでそれを分解します。
ファイルを読み込んでZend_Reflection_Fileを使うと、そのファイルの中にいくつクラスがあるか?などを調べてくれます。
その中で、クラスから関数を探索し、その関数の属性にあたる情報を下記のようにして取得できます。
<?php $path = "Sample.php" require $path; $autoloader = Zend_Loader_Autoloader::getInstance(); $ref = new Zend_Reflection_File($path); // 後で行レベルで内容を調べるため保持 $lines = file($path); foreach($ref->getClasses() as $cls) { // Zend_Reflection_Method $methods = $cls->getMethods(); foreach($methods as $method) { // 修飾子 $modifiers = join(" ", Reflection::getModifierNames($method->getModifiers())); // 関数名 $name = $method->getName(); // パラメータ $parameterNamesArray = array(); $params = $method->getParameters(); foreach($params as $param) { $parameterNamesArray[] = "$" . $param->getName(); } $parameters = join(", ", $parameterNamesArray); // シグネチャ $signature = sprintf("%s function %s (%s)", $modifiers, $name, $parameters); // 本体は行レベルで取得する $body = join("", array_slice($lines, $method->getStartLine(), $method->getEndLine() - $method->getStartLine())); // 出力 echo $signature . "\n" . $body . PHP_EOL; } }
タブとかはもちろん吹き飛んでしまうので出力はこんな具合になる。
public static function staticFunction ($param1, $param2) { echo "staticFunction"; }
これを何らかの命名規則のファイル(filepath_class_method.txtみたいな)に書きこんで、md5sumとかdiffとかで調べていけば、共通している部分の抽出ができるのではないか、と思う。
ちなみにこれをかけてみたら200行にも渡るファイルが発見され、それはそれでどうなんだ、ってなってるとこ。