Tetsujin’s blog

http://d.hatena.ne.jp/Tetsujin

PHPのソース整形ツール phpStylist

前回のphpCodeBeautifierに続いて、またまたソースを綺麗にするツール。
phpStylist - http://sourceforge.net/projects/phpstylist/

2007-06-29 released なので最近ですね。
Webからでもコマンドラインからでも叩けます。noticeが出るわ、 $HTTP_POST_FILESとか$HTTP_SERVER_VARS 使ってて中身はかなり衝撃でしたが*1、結果的にphpCodeBeautifierよりこのphpStylistのほうがまだ使えるかな?と感じました。


落として

$ wget http://nchc.dl.sourceforge.net/sourceforge/phpstylist/phpStylist-0.9beta.zip
$ unzip phpStylist-0.9beta.zip
  inflating: phpStylist.js
  inflating: phpStylist.php
  inflating: Readme.txt

とりあえずこんなのを作って、
pstyle

#!/bin/sh
php phpStylist.php $1 \
    --indent_size 4 \
    --keep_redundant_lines \
    --space_after_comma \
    --space_around_assignment \
    --align_var_assignment \
    --space_around_comparison \
    --space_around_arithmetic \
    --space_around_logical \
    --space_around_colon_question \
    --line_before_curly_function \
    --space_after_if \
    --else_along_curly \
    --add_missing_braces \
    --line_after_break \
    --space_inside_for \
    --indent_case \
    --vertical_array \
    --align_array_assignment \
    --space_around_double_arrow \
    --space_around_concat \
    --line_before_comment_multi \

こんな感じで。

$ ./pstyle before.php > after.php

use sampleのそのまま突っ込んでみます
before

<?php 
/***
 * phpStylist demonstration code
 * by Mr. Milk (aka Marcelo Leite)
 * mrmilk@anysoft.com.br
 */
$work_hours=12;
$time=$work_hours*2;
$developer=$poorguy;
$god=$$mrgates;
$wage=$work_hours/2;
$bonus=$wage*0.00001;
$warned=false;
$properties=array("gates"=>array("everything"=>"yes","anything"=>"yes","anything else"=>"yes","you"=>"completely"),"developer"=>array("an old car"=>"2 installments","modded computer"=>"almost","beer mug"=>"sure!"));
$warning="Mr. ".$developer.", you made ".$god." unhappy today.";
// developer's miserable life
for($you=$developer;$you<$god;$you++) {
// let's use his potential
if($work<=$time*4) {
$work++;
$sleep--;
$enrichGates();
}
// chickening out huh?
elseif($tired) {
if(!$warned) {
$scareToDeath($developer,$warning);
$bonus/=2;
}
elseif($bonus>0) 
$bonus=0;
else {
fire($developer);
$replacement=findIdiot();
hire($replacement,$wage/2);
}
}
// this guy can take it
elseif($wage>0) 
$wage--;
// have we really found who we've been looking for?
else {
$enrichGates();
$health_level=emergencyRoom($developer);
/* sanity check! */
switch($health_level) {
case "great":
fire($doctor);
unset($properties["developer"]);
unset($properties["gates"]["you"]);
cuckoosNest($developer);
$replacement=findIdiot();
hire($replacement,$min_wage);
break;
case "good":
case "bad":
backToWork();
break;
case "terminal":
fire($developer);
$replacement=$has_brother?"brother":"friend";
hire($replacement,$min_wage/2);
break;
default:
}
}
}
/***
 * Functions
 */
function emergencyRoom($who) {
$healthy=false;
$intern=0;
while(!$healthy&&$healthy!="end") 
$healthy=scrubsInternOpinions($who,++$intern);
$intern=0;
while(!$healthy&&$healthy!="end") 
$healthy=erInternOpinions($who,$intern++);
return $healthy;
}
function hire($who,$wage) {
$developer=new Slave();
$developer->person=$who;
$developer->setSalary($wage);
$cost=hrRoutines::getHiringCost();
$developer->setDebt($cost);
}
function fire($who) {
callSecurity();
getHimOut($who);
}
?> 

after

<?php
/***
 * phpStylist demonstration code
 * by Mr. Milk (aka Marcelo Leite)
 * mrmilk@anysoft.com.br
 */
$work_hours = 12;
$time       = $work_hours * 2;
$developer  = $poorguy;
$god        = $$mrgates;
$wage       = $work_hours / 2;
$bonus      = $wage * 0.00001;
$warned     = false;
$properties = array(
    "gates" => array(
        "everything"    => "yes",
        "anything"      => "yes",
        "anything else" => "yes",
        "you"           => "completely",
    ),
    "developer" => array(
        "an old car"      => "2 installments",
        "modded computer" => "almost",
        "beer mug"        => "sure!",
    ),
);
$warning = "Mr. " . $developer . ", you made " . $god . " unhappy today.";
// developer's miserable life
for ($you = $developer; $you < $god; $you++) {
    // let's use his potential
    if ($work <= $time * 4) {
        $work++;
        $sleep--;
        $enrichGates();
    }
    // chickening out huh?
    elseif ($tired) {
        if (!$warned) {
            $scareToDeath($developer, $warning);
            $bonus /= 2;
        } elseif ($bonus > 0) {
            $bonus = 0;
        } else {
            fire($developer);
            $replacement = findIdiot();
            hire($replacement, $wage / 2);
        }
    }
    // this guy can take it
    elseif ($wage > 0) {
        $wage--;
    }
    // have we really found who we've been looking for?
    else {
        $enrichGates();
        $health_level = emergencyRoom($developer);

        /* sanity check! */
        switch ($health_level) {
            case "great":
                fire($doctor);
                unset($properties["developer"]);
                unset($properties["gates"]["you"]);
                cuckoosNest($developer);
                $replacement = findIdiot();
                hire($replacement, $min_wage);
                break;

            case "good":
            case "bad":
                backToWork();
                break;

            case "terminal":
                fire($developer);
                $replacement = $has_brother ? "brother" : "friend";
                hire($replacement, $min_wage / 2);
                break;

            default:
        }
    }
}

/***
 * Functions
 */
function emergencyRoom($who)
{
    $healthy = false;
    $intern = 0;
    while (!$healthy && $healthy != "end") {
        $healthy = scrubsInternOpinions($who, ++$intern);
    }
    $intern = 0;
    while (!$healthy && $healthy != "end") {
        $healthy = erInternOpinions($who, $intern++);
    }
    return $healthy;
}
function hire($who, $wage)
{
    $developer = new Slave();
    $developer->person = $who;
    $developer->setSalary($wage);
    $cost = hrRoutines::getHiringCost();
    $developer->setDebt($cost);
}
function fire($who)
{
    callSecurity();
    getHimOut($who);
}
?>
  • たまに空行に空白が混じる
  • 適度な文字数での折り返しがない
  • ファイルの最後に^Mが入る
  • 上記のオプションで試しにMDB2.phpを突っ込んだら空っぽになった。(デフォではOK)

とかいろいろありますが、なかなか綺麗に整えてはくれます。phpCodeBeautifierより崩れない。(いや、まあ整形しようとして崩れたら困るんだが)
今後に期待かな?と思います。


以下、オプション一覧。間違ってるところがあったらごめんなさい。

全体

--indent_size n
インデントサイズの指定
--indent_with_tabs
インデントをTabにするか
--keep_redundant_lines
空行をつぶさない
--space_inside_parentheses
()の内側にスペースを入れる
--space_outside_parentheses
()の外側にスペースを入れる
--space_after_comma
,の後ろにスペースを入れる

演算子

--space_around_assignment
= .= += -= *= /= <<< 代入演算子の前後にスペースを入れる
--align_var_assignment
= 等の代入演算子が3つ以上固まれば位置を整える
--space_around_comparison
== === != !== > >= < <= 比較演算子の前後にスペースを入れる
--space_around_arithmetic
- + * / % 演算子の前後にスペースを入れる
--space_around_logical
&& || AND OR XOR << >> 論理演算子の前後にスペースを入れる
--space_around_colon_question
? : 3項演算子の前後にスペースを入れる

関数とクラス

--line_before_function
function, classの前行に空行を入れる
--line_before_curly_function
function, class の{を次の行にする
--line_after_curly_function
{の次に空行を入れる
--space_around_obj_operator
-> の前後にスペースを入れる
--space_around_double_colon
:: の前後にスペースを入れる

制御文(if, elseif, else, for, foreach, while, do, switch, break)に対して

--space_after_if
if等のキーワードの後にスペースを入れる
--else_along_curly
else, elseifの前で改行しない
--line_before_curly
{を次行に
--add_missing_braces
if等が1行でも、{}を入れる
--line_after_break
breakの後に空行
--space_inside_for
forの;の後ろにスペース
--indent_case
case, defaultの後をインデントする

配列と、文字列結合

--line_before_array
arrayの()を改行する
--vertical_array
arrayをkey => value, )毎に改行して表示する
--align_array_assignment
=>をそろえる
--space_around_double_arrow
=>の前後にスペース
--vertical_concat
文字列結合を縦にする
--space_around_concat
.の前後にスペース

コメント

--line_before_comment_multi
/* コメントの前に空行
--line_after_comment_multi
/* コメントの後ろに空行
--line_before_comment
// コメントの前に空行
--line_after_comment
// コメントの後ろに空行

*1:register_long_arraysをいじったりして、IE6で動きました。Firefox2はだめでした。