恥知らずのウェブエンジニア -web engineer, shameless

これは一歩を踏み出すことができない者たちのブログ

PSR-4(Autoloading Standard)を見ていく

要約ですので、所々省いている箇所あります。

オリジナルはこちら

www.php-fig.org

概要

  • ファイルパスからクラスをautoloadingする仕様
  • PSR-0も含め、その他のautoloadingの仕様と相互運用可能
  • このPSRはautoloadingされるためのファイルを配置する場所も記述している

仕様

  1. classはクラス、インターフェース、トレイトなどの構造を指す
  2. 完全修飾クラス名は下記の形式 \<NamespaceName>(\<SubNamespaceNames>)*\<ClassName>
    1. 完全修飾クラス名は、vendor namespaceで知られるトップレベルのネームスペースを持っていないといけません
    2. 完全修飾クラス名は、1つ以上のサブネームスペースを持ってもよい
    3. 完全修飾クラス名は、最後にクラス名をもたないといけない
    4. アンダースコアは完全修飾クラス名の中で特別な意味を持ちません
    5. 完全修飾クラス名は大文字/小文字組み合わせてもよい
    6. すべてのクラス名は大文字/小文字区別します
  3. 完全修飾クラス名に対応するクラス名をロードする時は、
    1. 完全修飾クラス名の先頭のネームスペースとサブネームスペース(ネームスペースプリフィックス)がベースディレクトリに対応します
    2. ネームスペースプリフィックス以後のサブネームスペースはベースディレクトリ内のサブディレクトリに対応します。ネームスペースのセパレータはディレクトリのセパレータに対応します。サブディレクトリ名はサブネームスペース名に大文字小文字含め対応しないといけない
    3. 最後のクラス名は.phpで終わるファイル名に対応します。ファイル名は大文字小文字含め最後のクラス名に対応していないといけません
  4. オートローダーの実装ではexceptionsをthrowしてはいけない。どのレベルのエラーも出してはいけない。戻り値も返すべきではありません

Examples

FULLY QUALIFIED CLASS NAME NAMESPACE PREFIX BASE DIRECTORY RESULTING FILE PATH
\Acme\Log\Writer\File_Writer Acme\Log\Writer ./acme-log-writer/lib/ ./acme-log-writer/lib/File_Writer.php
\Aura\Web\Response\Status Aura\Web /path/to/aura-web/src/ /path/to/aura-web/src/Response/Status.php
\Symfony\Core\Request Symfony\Core ./vendor/Symfony/Core/ ./vendor/Symfony/Core/Request.php
\Zend\Acl Zend /usr/includes/Zend/ /usr/includes/Zend/Acl.php
  • PSR4を実装したクラス例

Example Implementations of PSR-4 - PHP-FIG

  • cakephpは↑のをほぼそのまま使っている模様

cakephp/ClassLoader.php at master · cakephp/cakephp · GitHub

  • Codeigniter4のPSR4を実装したAutoloader

CodeIgniter4/Autoloader.php at develop · bcit-ci/CodeIgniter4 · GitHub


その昔PEARなどはライブラリを中央ディレクトリにイントールして使用していましたが、composerの登場により各プロジェクトごとにパッケージとして使うようになりました。
また名前空間のなかった時代の名残としてクラス名に'_‘で区切って擬似的に名前空間を作っていたり煩雑になったのを共通化しようよって感じかと!

PSR-5(PHPDoc Standard)はDRAFTなので、次はPSR-6(Caching Interface)へ・・・

PSR-6: # Introduction - PHP-FIG

PSR-3(Logger Interface)を見ていく

要約ですので、所々省いている箇所あります。

オリジナルはこちら

www.php-fig.org

概要

  • ロギングライブラリの共通インターフェースのドキュメント
  • ゴールはライブラリがPsr\Log\LoggerInterfaceを受け入れることでログ出力をシンプルかつ共通化を行う
  • フレームワークCMSは必要によってインターフェースを拡張してもよいが、インターフェースを遵守しなければいけない
  • こうすることでサードパーティライブラリでもログを集約することができる

仕様

基礎

  • LoggerInterfaceは8個のメソッドを提供し、レベルは8個(debug, info, notice, warning, error, critical, alert, emergency)
  • 9番目のメソッドlogは第一引数にログレベルを受け取る。ログレベル定数の一つを受け取ったメソッドの結果は、各レベルごとのメソッドの結果と同じでなければならない
  • 定義されていないレベルを引数として受け取った場合、Psr\Log\InvalidArgumentExceptionをthrowしなければならない
  • ユーザはカスタムレベルを使うべきではありません

メッセージ

  • 各メソッドはメッセージとしてstringか、__toString()を持つオブジェクトを受け取る。
  • 実装者はオブジェクトを何らかハンドリングしてもよいですが、そのケースではない時は、stringにキャストしなければいけません
  • メッセージは配列の値から置換できるプレースホルダーを含んでもよい
  • プレースホルダーの命名は配列のキーと一致しなければならない
  • プレースホルダーは{}で囲まないといけない。囲んでいる中にホワイトスペースを入れてはいけない
  • プレースホルダーはA-Z, a-z, 0-9, _, .だけを使うべき。それ以外は今後のプレースホルダー仕様変更用に予約されています
  • 実装者は、プレースホルダーを表示用にエスケープ、翻訳してもよい。ユーザは事前にプレースホルダーの値をエスケープすべきではない。

プレースホルダーの例

/**
 * Interpolates context values into the message placeholders.
 */
function interpolate($message, array $context = array())
{
    // build a replacement array with braces around the context keys
    $replace = array();
    foreach ($context as $key => $val) {
        // check that the value can be casted to string
        if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) {
            $replace['{' . $key . '}'] = $val;
        }
    }

    // interpolate replacement values into the message and return
    return strtr($message, $replace);
}

// a message with brace-delimited placeholder names
$message = "User {username} created";

// a context array of placeholder names => replacement values
$context = array('username' => 'bolivar');

// echoes "User bolivar created"
echo interpolate($message, $context);

Context

  • 各メソッドは、配列をコンテキストデータとして受け取る
  • これはストリングでは表現できない補足情報を持たせることを意味します
  • 実装者はコンテキストデータを出来る限り寛大に扱わなければいけない
  • コンテキストデータによって、exceptionをthrowしたり、エラー、ワーニング等々を出してはいけない

  • もしExceptionオブジェクトがコンテキストデータで渡された時、それはexceptionキーの中になければいけない

  • exceptionのロギングは共通パターンにすることで、実装者はexceptionからスタックトレースを抽出することができます
  • 実装者はexceptionキーの値が実際にExceptionか検証しなければいけません

ヘルパークラスとインターフェース

  • Psr\Log\AbstractLoggerクラスを継承することで簡単にLoggerInterfaceと、汎用のlogを提供します
  • 同様にPsr\Log\LoggerTraitを使うことで実装がするのは汎用のlogメソッドだけです
  • しかしtraitsはインターフェースを実装せきないため、この場合はLoggerInterfaceを実装する必要があります
  • Psr\Log\NullLoggerはインターフェースと共に提供されます。これはユーザによってログがいらない場合にブラックホール用のインターフェースを提供します。しかしコンテキストデータの生成コストがかかる場合は条件付きロギングの方が良いです
  • Psr\Log\LoggerAwareInterfacesetLogger(LoggerInterface $logger)メソッドのみ含み、任意のインスタンスをロガーで接続するフレームワークで使用できます
  • Psr\Log\LoggerAwareTraitトレイトはどのクラスでも簡単に等価なインターフェースを提供します。$this->loggerでアクセスできます
  • Psr\Log\LogLevelは8個のログレベルを定数として持っています

色々composer経由で各種ライブラリを組み合わせて作るのが主流になっているので、その際個別にログ出力を実装しているとフォーマット、ディレクトリ等々バラけてしまいます。 またログレベルがバラバラだと環境別に出力の設定をしたい時個別にそれぞれしないといけません。

そこのインターフェース揃えれば、共通化できるし、差し替えも可能って感じかと!

PSR-4(Autoloader)へ続く・・・

PSR-4: Autoloader - PHP-FIG

PSR-2(Coding Style Guide)を見ていく

要約ですので、所々省いている箇所あります。

オリジナルはこちら

www.php-fig.org

要点

PSR-2はPSR-1を継承/拡張した基本的なコーディング基準

開発者間でのコードリーディング時の認識のズレを減らすためのガイドライン

ルール自体にではなく、ルールを共有することに意味がある

概要

  • “coding style guide” PSR [PSR-1]を守る
  • インデントは4スペース
  • 1行内の文字数は上限はないが、120文字以内、できれば80文字以内に収める
  • namespaceの宣言後には空行を、use宣言ブロックの後にも空行入れる
  • classの開きブレースは次の行に、閉じブレースはボディ最後の次の行に
  • methodの開きブレースは次の行に、閉じブレースはボディ最後の次の行に
  • property と methodには必ずアクセス修飾子を。abstractfinalはアクセス修飾子に前に、staticはアクセス修飾子の後ろに
  • 制御構造の後には1スペース、メソッド呼び出しの場合は除く
  • 制御構造の開きブレースは同じ行で、閉じブレースはボディ最後の次の行で
  • 制御構造の開き丸括弧の後にはスペースを置かない、閉じ丸括弧の前にはスペースを置かない

例としてはこちら

<?php
namespace Vendor\Package;

use FooInterface;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

class Foo extends Bar implements FooInterface
{
    public function sampleMethod($a, $b = null)
    {
        if ($a === $b) {
            bar();
        } elseif ($a > $b) {
            $foo->bar($arg1);
        } else {
            BazClass::bar($arg2, $arg3);
        }
    }

    final public static function bar()
    {
        // method body
    }
}

全般

ファイル

  • 改行はUnix LF
  • ファイル最後には空行を
  • ?>の閉じタグは不要

phpキーワード、True/False/Null

  • phpキーワード、true, false, nullは小文字で

methodの引数

  • 引数リストはの,の後にはスペースを
  • 引数にデフォルト値があるものは最後に
  • 引数を複数行にする場合は開き丸括弧の後に改行し、各行に1つずつ

PSR-3(Logger Interface)へ続く・・・ ここからが本番・・・

PSR-3: Logger Interface - PHP-FIG

PSR-1(Basic Coding Standard)を見ていく

諸々あってPSRを順番に確認していく・・・!

オリジナルはこちら

www.php-fig.org

概要

  • <?php<?=タグのみ使用。閉じタグはなし
  • UTF-8 BOMなし
  • シンボル(クラス、関数、定数)を宣言するファイルと副作用のあるもの(出力、iniの変更など)は分ける
  • namespace,クラス名は“autoloading” PSR: [PSR-0, PSR-4]に従う
  • クラス名は、StudlyCaps(単語の先頭文字を大文字。UpperCamelCase?)で定義(ex:FooBarHogeClass)
  • クラス定数は大文字で、区切りはアンダースコアで定義
  • メソッド名はcamelCaseで定義

ちょっと気になったもの

  • シンボル(クラス、関数、定数)を宣言するファイルと副作用のあるもの(出力、iniの変更など)は分ける

例としては下記のようなものが上げられていました。

副作用あるもの、設定と実装は分けましょう的な感じかと

<?php
// side effect: change ini settings
ini_set('error_reporting', E_ALL);

// side effect: loads a file
include "file.php";

// side effect: generates output
echo "<html>\n";

// declaration
function foo()
{
    // function body
}

<?php
// declaration
function foo()
{
    // function body
}

// conditional declaration is *not* a side effect
if (! function_exists('bar')) {
    function bar()
    {
        // function body
    }
}
  • クラス名は、StudlyCaps(単語の先頭文字を大文字。UpperCamelCase?)で定義(ex:FooBarHogeClass)

StudlyCapsは元々?は大文字小文字が入り乱れるようなのですが、ここでは実質UpperCamelCaseと同義だと思われ。

Studly caps - Wikipedia

PSR-2へ続く・・・

PSR-2: Coding Style Guide - PHP-FIG

「英語は1年でマスターできる」を読んだ

最近、英語の勉強を本格的に始めてます。

海外旅行の時にローカルな所行きたい、海外カンファレンス行きたい、英語LTしたい、ワンチャン海外で働きたい、 そもそもgithub,ドキュメントとかさくっと読みたいとかとかが動機です。

まずは英語のpodcast聞いたり、英会話クラス行き始めています。

しかしそれだけだと明確な進捗が測りづらく計測の仕方を考えないといけないなと感じていました。少しずつ英語に慣れてきた気はするんですが・・・

そんな時に立ち寄った本屋に平積みされていた「英語は1年でマスターできる」を読んでみました。

概要

筆者はソフトバンク孫正義社長の秘書をしていた方です。

英語での交渉に同席した時、全く会話が理解出来ていない事で、「このままではクビにされる!」という所から1年で英語で交渉できるまで上達するまでに行ったことが紹介されています。

印象に残った事

  • 英語で何をしたいか明確にする
  • 勉強するのは、そのために必要なことのみに絞る
    • ex : 英語での交渉が目的なら、カジュアルな言い回し/雑談/発音/ライティングは切り捨てるなど
  • 意思疎通できればよいので、簡単な単語だけでよい。複数の言い回しは不要
    • 1000時間勉強すれば、必ず英語ができるようになる。だいたい1日3時間
    • そのために英語を勉強する時間が固定化してスケジューリング
  • リスニングは映画を英語テキストでシャドーイングが効果的
    • 映画は自分が英語でやりたいシーンに近いものを選び、1つのものを徹底的に

自分に置き換えて考えてみる

感想としては、かなり腹オチしました!

ちょうど英語を勉強し始めたものの英語力が上がっているかどうか、このままで上がっていくのか不安に感じていました。 なので、

  • 目的を絞る。それ以外は二の次
  • 意思疎通が目的なので、微妙な言い回しをする必要はない
  • 単語はすでに知っているもので事足りる

というのはかなり納得感がありました。

ちょうどrebuildでも細かい言い回しする必要なんてないよねっていう話も出ていました。

rebuild.fm

早速自分に置き換えて実践してみようと思います。

英語を学んで何をしたいか目的を明確にする

冒頭にある通り、英語でエンジニアリングの話ができるようになるっていうのが最大の目的です。 なので、フォーカスすべきはリスニング、スピーキングになります。

微妙な言い回し、ライティング、リーディングは切り捨て対象です。

スピーキング強化のために

この本を読む前からですが、ビジネスシーンを対象とした英会話クラスに申し込みました。

テキストを見る限り、面接/プレゼン/仕事の依頼の仕方などの時に使うフレーズが中心なので、 ちょうど本の中にもあった、「目的のシチュエーションに沿ったスピーキング」が経験できそうです。

リスニング強化のために

本にあった通り、自分の目標のシチュエーションに近い映画を、英語テキストでシャドーイングしまくるという事をやってみようかと。

エンジニア系の映画という事で真っ先思いついたのは「ソーシャルネットワーク」でした。 次に英語のテキストを手に入れようと手に入れようと、文中にもあったスクリーンプレイを見てみました。

www.screenplay.jp

しかし肝心の「ソーシャルネットワーク」のテキストがありませんでした><
ですが、ググると普通にpdfで公開されていましたw

http://flash.sonypictures.com/video/movies/thesocialnetwork/awards/thesocialnetwork_screenplay.pdf

とは言え、164ページ印刷するのは流石に億劫なんで英語字幕のあるもの動画で行うことにしました。

itunes,amazon primeは英語字幕が現時点では非対応でしたので、netflixを利用することにしました。 netflixは英語コンテンツも豊富で字幕設定/データのDLができます。 またiphoneだと10秒のみ巻き戻せるので聞き取りづらい所も繰り返し再生することができます。

なので、通勤時間を利用してリスニング、シャドーイングしていこうと思います。

www.netflix.com

まずはこれら実践してみます! そして一ヶ月後くらいに上記を振り返りしてみようかと!

余談

とにかく英語に触れる機会を増やそうということで、PCやサイトの言語設定を諸々英語にしてみました。

けっこうこれだけでも雰囲気変わるので意識付けとしていい感じです。

あとサイトによっては、
.jpではログインできるのに、英語設定だと.comにつながってログインできないものがあったりしました。アカウントの持ち方が別々なのかなーと。
これまで多言語対応したものを実装した経験がないので、自分だったらどう実装するかなーとか考えるきっかけになって面白かったです。

The difference of default charset when connect to mysql with php

When the monitors the product if use codeigniter,fuelphp that PHP framework by New Relic, execute query SET NAMES foo when every connect to mysql.

This is not just problem, but execute when every connect and it was somehow eyesore, so I fix to don’t execute that query.

the code execute query SET NAMES foo

The case of codeigniter * mysqli, it is execute this code↓

CodeIgniter/mysqli_driver.php at 9e17059bf8d277058d1de23390e388b5fa0cc26a · bcit-ci/CodeIgniter · GitHub

This product use UTF-8 charset, and configure my.cnf too.

So I thought in the first place, this is not need it. comment out set_charset() for now. Then, don’t execute SET NAMES foo and don’t garbled.

Only one environment garbled characters

It' OK. just as planned. I apply other environment this fixing. one environment garbled characters. it seemed garbled by latin1.

There is difference in default charset by mysql library

The result i investigated, There is difference in default charset by mysql library.

PHP: Mysqlnd - Manual

MySQL :: MySQL PHP API :: 2.4 Choosing a library

PHP: Choosing a library - Manual

library default charset
mysqlnd the server default charset
libmysql charset selected when build(latin1 if no selected)

Finally, the cause of garbled is the server is used libmysql.

How to fix,

  • use mysqlnd
  • rebuild libmysql and select charset
  • select charset by mysqli_options (selectable charset without SET NAMES foo) PHP: mysqli::options - Manual

This is a minute thing, but it would be better a few query!

phpからmysqlに接続する際のデフォルト文字コードについて

PHPフレームワークでcodeigniter,fuelphpなど使っているプロジェクトをnew relicで見てみると毎回DB接続の度にSET NAMES ~~~という文字コードを設定するクエリを毎回発行していました。

別にこれだけでどうってことはないのですが、毎接続時に発行されているし、なんか目障りだったので発行しないようにしたくなりました。

SET NAMES を発行している箇所

codeigniter * mysqliでは、SET NAMES ~~~を発行しているのは下記のようです。 CodeIgniter/mysqli_driver.php at 9e17059bf8d277058d1de23390e388b5fa0cc26a · bcit-ci/CodeIgniter · GitHub

対象のプロジェクトではmysql文字コードUTF-8を使っており、my.cnfにもそのように設定していました。

なので、そもそもこれしなくていいんじゃね?ってことで試しに、mysqli_driver.phpを継承したクラスを作り、set_charset()コメントアウトしてみました。 そうするとSET NAMES ~~~の消えて、挙動も問題なさそうでした。

とある環境のみ文字化け

で、よしよしと他の環境にも反映を行っていった所、ある環境のみ文字化けをしてしまいました。 文字化け具合的にlatinっぽい文字化けでした。

ライブラリによってデフォルト文字コードの扱いが違う

諸々調べるとPHPが使っているライブラリによってデフォルトの文字コードに違いがあるようでした。

PHP: Mysqlnd - Manual

MySQL :: MySQL PHP API :: 2.4 Choosing a library

PHP: どのライブラリを選ぶか - Manual

ライブラリ デフォルトの文字コード
mysqlnd サーバーのデフォルト文字コード
libmysql ビルド時の文字コード(デフォルトではlatin1)

文字化けしているサーバーがlibmysqlを使われていたので文字化けしていたの原因のようです。

対応としては、

これらあたりでいけそうです。

細かいとこですが、できるだけクエリは少なくしたいということで!