143
141

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

コード改善に役立ちそうなPHPライブラリ・ツール

Last updated at Posted at 2015-02-18

最近PHPを使っていて、便利だなと思ったライブラリ・ツールを紹介します。
特定のフレームワークに依存しないので、既存のコードに組み込んで利用することもできます。

なお、この記事内のサンプルコードは、カレントディレクトリにComposerがインストールされているのを前提としています。1
実際にコードを書いて試してみたい人は、composer.pharがあるディレクトリで、以下のコマンドを入力して下さい。

mkdir public
php composer.phar init -n

以下のようなファイル・ディレクトリ構成ができたはずです。

├── composer.json
├── composer.phar
└── public

Monolog

「運用中のサービスにバグが見つかったけど、再現方法がわからない」。そんな困った事態にならないよう、Monologで手がかりになる値を残しておきましょう。

Monologはphp composer.phar require monolog/monolog でインストールできます。

試しに簡単なログ出力をやってみましょう。public/index.phpを以下のように書いてください。

index.php
<?php
require '../vendor/autoload.php';
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

// Monologでログを出力してみる
$log = new Logger('cool-php-libraries');
$log->pushHandler(new StreamHandler('../logs/app.log', Logger::DEBUG));
$log->addInfo('トップページの表示');
$log->addError('エラーメッセージ');
$log->addDebug('デバッグ用のメッセージ');

php -S localhost:8080 -t publicビルトインウェブサーバーを立ち上げた状態で http://localhost:8080/ にアクセスしてください。logs/app.logに「トップページの表示」、「エラーメッセージ」、 「デバッグ用のメッセージ」というメッセージが出力されているはずです。

pushHandlerメソッドに渡したStreamHandlerがログの出力先を表すHandlerクラスです。これを書き換えることで出力先をファイルにしたり、メールで送ったり、DBに登録したりと、色々変更することができます(複数指定することもできます)。

StreamHandlerの第二引数に指定しているのがログの出力レベルです。Monologでは、レベルの低い順に以下が規定されています。

  • DEBUG
  • INFO
  • NOTICE
  • WARNING
  • ERROR
  • CRITICAL
  • ALERT
  • EMERGENCY

ログ出力に使っているaddほにゃららメソッドのほにゃららは上記のレベル名で、Handlerクラスで指定したレベル未満のメソッドは、たとえ書いてあってもどこにも出力されません。
例えば、上のコード例ではStreamHandlerLogger::DEBUGを指定しているので、すべてのレベルのログがlogs/app.logに出力されますが、Logger::INFOに変更すれば、addDebugメソッドの内容は出力されなくなります。
つまり、Handlerクラスに指定するログの出力レベルを環境によって変更できるようにしておけば、簡単に出力する/しないを切り替えることができます。

Chrome Logger & FirePHP

Chrome or Firefoxなら、echoを使うよりスマートなやり方でデバッグできます。

ChromeならChrome Logger、FirefoxならFirePHP2をインストールすると、開発者向けコンソールでMonologのログ出力を表示させることができます。PHPコードの変更は、以下のように、ChromePHPHandler 3FirePHPHandlerを加えるだけです。

index.php
<?php
require '../vendor/autoload.php';
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\ChromePHPHandler;
use Monolog\Handler\FirePHPHandler;

// Monologでログを出力してみる
$log = new Logger('cool-php-libraries');
$log->pushHandler(new StreamHandler('../logs/app.log', Logger::DEBUG));
$log->pushHandler(new ChromePHPHandler(Logger::DEBUG));
$log->pushHandler(new FirePHPHandler(Logger::DEBUG)); 
$log->addInfo('トップページの表示');
$log->addError('エラーメッセージ');
$log->addDebug('デバッグ用のメッセージ');

ただ、FirePHPは、私の環境(Mac 10.9.5、Firefox 35.0.1、FirePHP 0.7.4、Firebug 2.0.8)では日本語のログが文字化けしました。日本語のログは出力しないようにした方が無難かもしれません。

FluentPDO

ユーザーの入力値によって文字列でSQL文を作る仕様のコードを書いたら、リリース後に条件によってSQLが構文エラーになるバグが見つかった、なんてことありませんか?
FluentPDOなら、文字列ではなくPHPのメソッドでSQL文をつくることができます。
インストールはphp composer.phar require lichtner/fluentpdo:dev-masterでできます。
以下のように、fromselectwhereorderByといったSQL文と似た名前のメソッドでSQL文を作れます。

index.php
<?php
require '../vendor/autoload.php';
$db = '../example.db';
$dsn = 'sqlite:' . $db;
if (!file_exists($db)) {
    // データベースの初期化
    $pdo = new PDO($dsn);
    $sql = <<<EOT
create table record(
    id integer primary key autoincrement,
    name text,
    point integer
);
EOT;
    $pdo->query($sql);

    $fpdo = new FluentPDO($pdo);
    $values = [
        ['name' =>'山田太郎', 'point' => 500],
        ['name' =>'山田花子', 'point' => 300],
        ['name' =>'鈴木一郎', 'point' => 890],
        ['name' =>'山本五郎', 'point' => 90],
    ];
    foreach ($values as $value) {
        $fpdo->insertInto('record', $value)->execute();
    }
} else {
    $pdo = new PDO($dsn);
    $fpdo = new FluentPDO($pdo);
}
$query = $fpdo->
    from('record')->
    select(null)->
    select('name')->
    select('point')->
    where('point > ?', 100)->
    orderBy('point DESC');
?>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>cool-php-libraries</title>
</head>
<body>
   <h1>cool-php-libraries</h1>
    <ul>
    <?php foreach ($query as $q): ?>
    <li><?php echo htmlspecialchars($q['name']); ?> <?php echo htmlspecialchars($q['point']); ?>点</li>
    <?php endforeach; ?>
    </ul>
</body>
</html>

select(null)と書いていますが、FluentPDOのselect文はデフォルトではselect *になるようで、特定のカラムのみ呼び出したい場合は、このコードで一旦デフォルトの設定を無効にする必要があるようです。

デバッグ機能も用意されていて、どんなSQL文が生成されるのかを見ることができます。先に紹介したMonologと組み合わせるなら、こう書きます。

index.php
<?php
require '../vendor/autoload.php';
// Monologの初期化処理は省略
$dsn = 'sqlite:../example.db';
$pdo = new PDO($dsn);
$fpdo = new FluentPDO($pdo);
$fpdo->debug = function ($query) use ($log) {
    $log->addDebug($query->getQuery());    
};

phpdotenv

PHP 5.4以降ではビルトインウェブサーバーという機能があるので、Apacheやnginxをインストールしなくても開発することができるようになりました。
ただ、環境変数をApacheやnginxの設定ファイルに書く前提で設計してしまうと、開発環境でどうするのかという問題が発生します。
そんな時、phpdotenvを使うと、どの環境でも共通の方法で環境変数を参照できるようになります。
インストールはphp composer.phar require vlucas/phpdotenvでできます。
使い方は、loadというメソッドに.envファイルがあるディレクトリを渡すだけです。

index.php
<?php
require '../vendor/autoload.php';
// 環境変数の読み込み
Dotenv::load(__DIR__ . '/..');

なお、本番環境でDocumentRootの下に.envを置くと、当然ブラウザからアクセスできてしまうので、.envだけ403 Forbiddenになるようにしておくか、DocumentRootの上に置くように設計しておいたほうがいいでしょう。

.envファイルは、以下のように変数名と値をイコールで繋いで書きます。

.env
S3_BUCKET=dotenv
SECRET_KEY=souper_seekret_key

必須の環境変数がある場合は、以下のように書いておくと書き忘れにすぐ気づけます。

index.php
require '../vendor/autoload.php';
// 環境変数の読み込み
Dotenv::load(__DIR__ . '/..');
// DATABASE_DSNが定義されていないとエラーになる
Dotenv::required('DATABASE_DSN');

2016/07/04追記

FluentPDO公式サイトのURLが変わっていたので変更しました。@kt81 さんご指摘ありがとうございました。

2016/09/13追記

2016/07/04に変更したFluentPDO公式サイトのURLがまた変更されたようです。また変更されたとき修正するのが面倒なので、この記事ではGitHubのURLを貼っておきます。

  1. ... Composerについて詳しくはこちらを参照してください。http://qiita.com/tadsan/items/a0a14e58aa4d88f19624#composer

  2. ... FireBugも併せてインストールしてください

  3. ... ChromePHP=Chrome Loggerの旧名

143
141
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
143
141

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?