PHPプロ!TIPS+

1. PHPからJSON作成を扱う

近頃、データ形式のやりとりに「JSON」を使う場面が多くなってきています。PHPのデータを簡単にJSON形式に変換するライブラリには、「PEAR::Services_JSON」「Zend/Json.php」「php-jsonモジュール」等があります。それらの簡単な使用方法を紹介します。

●PEAR::Services_JSONの場合

現在このパッケージはPEARに正式登録されていません。その為、pearコマンドではインストールすることができませんので、以下のページよりダウンロードを行い、設置してください。

ダウンロード(http://mike.teczno.com/JSON.tar.gz)

あとは、非常に簡単なコードでJSON形式のデータに変換することができます。

<?php
require_once "JSON.php";

$arr array(
    array(
        
"name" => "アシアル",
        
"url"  => "http://www.asial.co.jp/"
    
),
    array(
        
"name" => "PHPプロ",
        
"url"  => "http://www.phppro.jp/"
    
)
);

$json = new Services_JSON;
$encode $json->encode($arr);
header("Content-Type: text/javascript; charset=utf-8");
echo 
$encode;
?>

これだけで、PHPの配列をJSON形式で出力することができます。実際に出力されたデータは以下のようになっています。

[{"name":"\u30a2\u30b7\u30a2\u30eb","url":"http://www.asial.co.jp/"},{"name":"PHP\u30d7\u30ed","url":"http://www.phppro.jp/"}]

これをJavaScript側でeval()をすることでObjectとして扱うことができます。

//XMLHttpRequestの完了時のアクション
function ajax_complete_action(request) {
    var json = eval(request.responseText);  // ← この行
    var html = "";
    for (var i = 0; i < json.length; i++) {
        html += '<a href="' + json.url + '">' + json.name + '</a>';
    }
    document.body.innerHTML = html;
}

また、「Zend/Json.php」、「php-jsonモジュール」の場合も以下のように簡単に変換することができます。

●Zend/Json.phpの場合

Zend Framework(http://framework.zend.com/)をダウンロードしinclude_pathの 通った場所に設置します。

<?php
require_once "Zend/Json.php";
$encode Zend_Json::encode($arr);
header("Content-Type: text/javascript; charset=utf-8");
echo 
$encode;
?>

●拡張モジュールのphp-jsonモジュールを使用する場合

php-json(http://www.aurore.net/projects/php-json/)からダウンロードし extension_dirに配置します。(なお、このモジュールはPHP5.2に追加される予定です)

そして、php.iniで

extension=php_json.so (Linuxの場合)
extension=php_json.dll (Windowsの場合)

とするか、もしくはdl()関数で呼び出します。

<?php
//php.iniで設定してない場合、dl()で読み込む
if (!extension_loaded("json")) {
  
dl("./json.so"); // エクステンションのロード
}
$encode json_encode($arr);
header("Content-Type: text/javascript; charset=utf-8");
echo 
$encode;
?>

※上記のコードはいずれも文字コードをUTF-8にしないとうまく動作しません。

今後、ますますAjaxアプリ等が増えていき、JSONを使う場面も出てくると思われます。 そんな時にはこれらのライブラリを検討してみてはいかがでしょう。

2. mb_strlen()関数の落とし穴

mb_strlen()関数は、日本語などのマルチバイト文字列の文字数をカウントする関数ですが、気をつけて使わないと思わぬバグの原因になってしまうことがあり ます。

<?php
$str 
'日本語にほんご';
var_dump(mb_strlen($str));
?>

このスクリプトを実行すると、多くの場合は

int(7)

と、正しい結果が表示されますが、環境によってはint(12)やint(9)など、変な値が表示されてしまう場合があります。

これは、PHPの内部エンコーディングが文字列のエンコードと異なっている時に起こります。

<?php
$str 
'日本語にほんご';
var_dump(mb_strlen($str'SJIS'));
?>

というように、mb_strlen()関数の第2引数に$strの文字エンコードを指定すると、PHPの内部エンコーディング設定に関わらず正しく動作するようになります。環境が変わったら突然おかしくなったということを防ぐためにも、第2引数で文字エンコードを指定するようにすることをお勧めします。mb_strlen()関数だけでなく、mb_strwidth()関数など、マルチバイト文字列関数はオプションの引数で文字エンコードを指定できるものが多いので気をつけてください。

このように、PHPの関数には引数がオプションとなっているものでも、指定しないと動作がおかしくなる場合があったり、指定すると大変便利に使えたりする関数がいろいろあります。マニュアルをいつもより少し詳しく見てみるだけでも、新たな発見があるかもし れません。

mb_strlen: http://www.phppro.jp/phpmanual/php/function.mb-strlen.html

3. str_replace、便利な所と注意点

指定した文字列を置換してくれるstr_replace()関数。この関数、全ての引数に文字列だけではなく配列も使用でき、とても便利です。ただ、便利だからとあんまり調子に乗ると・・・?

今回は、str_replace()関数の使用法と、その際のちょっとした注意点について紹介します。

str_replace()に関しては以前のTIPSメーリングリスト
(http: //www.phppro.jp/phptips/archives/vol2/)でも少し触れられていますが、引数を配列に使用した際の挙動について、簡単におさらいしておきましょう。

以下のように、第1引数に配列、第2引数に文字列を指定すると、配列の各値に該当する文字列が全て、第2引数に指定した文字列に置換されます。

<?php
$search 
array("a""b""c""d");
$replace "Z";
$subject "abcde";

$result str_replace($search$replace$subject);

var_dump($result);
?>

結果:
string(5) "ZZZZe"

第1、第2引数が共に配列を指定した場合、第1引数の各要素に対応した第2引数の要素が置換に使用されます。第2引数の方が要素数が少なく、対応する要素がない場合は、空文字列""に置換されます。

<?php
$search 
array("a""b""c""d""e");
$replace array("1""2""3""4");
$subject "abcde";

$result str_replace($search$replace$subject);

var_dump($result);
?>

結果:
string(4) "1234"

置換対象の第3引数にも配列が使用できて、その場合、第3引数の各要素に対して順次置換が行われていきます。

<?php
$search 
array("a""b""c""d");
$replace array("1""2""3""4");
$subject array("abc""dcba");

$result str_replace($search$replace$subject);

var_dump($result);
?>

結果:
array(2) {
  [0]=>
  string(3) "123"
  [1]=>
  string(4) "4321"
}

このように、str_replaceは配列を引数としてとることで非常に便利に使えます。

ただ、上記のように配列を引数として使用する際には、少し癖のある動作が存在します。それは、再帰的な置換が行われるという点と、2次元以上の配列を用いた場合です。

まず、この関数は第1引数の配列の先頭から順に、置換対象の文字列に対して再帰的に置換をしていきます。

<?php
$search 
array("a""b""c""1");
$replace array("1""2""3""4");
$subject "abcd";

$result str_replace($search$replace$subject);

var_dump($result);
?>

結果:
string(4) "423d"

この結果は、一度"a"が"1"に置換された後、さらに"1"が"4"で置換されたものです。なので、再帰的な置換を行いたくない場合は、第2回のTIPSメーリングリスト(http: //www.phppro.jp/phptips/archives/vol2/)で取り上げられているとおり、strtr関数を使うとよいでしょう。

また、引数で使用できる配列は、2次元以上の配列には対応していません。第1、第2引数に2次元以上の配列を使用しようとすると、Noticeを吐いて強制的に文字列型へ型変換したものを置換に使用します。

<?php
$search 
array(array("a""b"), "c""d"array("e""f"));
$replace array(array("1""2"), "3""4""5""6");
$subject array("abcdef""This is Array");

$result str_replace($search$replace$subject);

var_dump($result);
?>

結果:
Notice: Array to string conversion in C:\usr\hoge.php on line 6
array(2) {
  [0]=>
  string(6) "ab34ef"
  [1]=>
  string(9) "This is 5"
}

第3引数に2次元以上の配列を指定した場合には、その部分に関しては一切の置 換が行われず、そのままの内容が返されます。

<?php
$search 
array("a""b""c""d");
$replace array("1""2""3""4");
$subject array("ab""cd"array("ab""cd"));

$result str_replace($search$replace$subject);

var_dump($result);
?>

結果:
array(3) {
  [0]=>
  string(2) "12"
  [1]=>
  string(2) "34"
  [2]=>
  array(2) {
    [0]=>
    string(2) "ab"
    [1]=>
    string(2) "cd"
  }
}

そのため、2次元以上の配列の中身を置換しようと考える場合は、相応の処理で1次元まで落とし込む必要があります。

なお蛇足ですが、これらの挙動は、PHP5から追加されたstr_ireplace関数でも同 様です。

普段使う分には余り気にしないような点ですが、頭の片隅にとどめておくと何かのときに役に立つかもしれません。

str_replace : http://www.phppro.jp/phpmanual/php/function.str-replace.html

バックナンバーについて

TIPS-MLは、毎週金曜日に更新され、新しい記事が掲載されます。

Tipsꗗy[W 

Pick Up Q&A

Q
負荷時のmysql_connect()エラー
 このエントリーをはてなブックマークに追加 
A
これはPHPというよりOSまたはMySQLのコミュニティで質問されたほうがいいと思います。 ぱっと思いついた範囲で記すと MySQL等のDBに「ある時点において同時に接続可能なクライアントの最大数」に制限があるよう...

>>続きを読む

今回のような実践的な経験がエンジニアのキャリアに繋がると思います。是非サービスを成功させて下さい!

▲解説者:岡本(アシアル株式会社 教育コーディネーター兼 システムエンジニア)