empty と isset と is_null ini_set と display_errors error_reporting
by user
Comments
Transcript
empty と isset と is_null ini_set と display_errors error_reporting
はまりどころ? 特に断りがなければ PHP5 での記述ということで。 empty と isset と is_null 値 if($var) if(empty($var)) if(isset($var)) if(is_null($var)) $var=1 TRUE FALSE TRUE FALSE $var=""; FALSE TRUE TRUE FALSE $var="0"; FALSE TRUE TRUE FALSE $var=0; FALSE TRUE TRUE FALSE $var=NULL; FALSE TRUE FALSE TRUE $var FALSE TRUE FALSE TRUE $var=array() FALSE TRUE TRUE FALSE $var=array(1) TRUE FALSE TRUE FALSE 値(中身)があるかないかで if($var) と if(empty($var)) は正反対、 変数(入れ物)があるかないかで if(isset($var)) と if(is_null($var)) は正反対になる。 PHP Manual:PHP 型の比較表 http://www.php.net/manual/ja/types.comparisons.php ゆどうふの湯豆腐ろぐ:$_POST、$_GET のよくある間違い http://d.hatena.ne.jp/yudoufu1/20060628 ini_set と display_errors マスターの php.ini で display_errors = Off のとき、エラーが発生してもブラウザのほうにはエラー 表示されない。 開発中(テスト中)はエラーを表示させるために、コード内で ini_set('display_errors', '1'); などとすることがあるが、これは致命的なエラーの場合はエラー表示しないようになっている。 まぁ、場合によってはそのコードを書いた php ファイル自体が fatal error や syntax error なんてこと もあるわけだから、ini_set するより先に処理が停止していることもあるわけで。 ということで、変にはまりたくなければ php.ini や .htaccess で設定したほうが無難そう。 PHP Manual 実行時設定 http://www.php.net/manual/ja/errorfunc.configuration.php#ini.display-errors error_reporting 1 PHP 5 では、E_ALL に E_STRICT は含まれないというところ。 error_reporting = -1 と指定した場合は E_STRICT も含まれるみたい。 PHP Manual:error_reporting http://www.php.net/manual/ja/function.error-reporting.php PHP タグと短縮形 html に php コードを埋め込む際に <?php echo 'Hello World!!' ?> としたりするが、php.ini の short_open_tag が on ならば <? echo 'Hello World!!' ?> とすることができ、さらに <? echo のショートカットである <?= 'Hello World!!' ?> が利用できる。 php.ini ディレクティブに関する説明 http://www.php.net/manual/ja/ini.core.php#ini.short-open-tag include_path と include include 'foo/bar/hoge.php'; とやると、include_path から検索される。 include './foo/bar/hoge.php'; の場合はリクエストで呼ばれたファイルから相対パスでの読み込みとなり注意が必要だが、 include_path は使われないため高速になる。 include '/home/user/foo/bar/hoge.php'; のような絶対パスならばはまることもないため、予めプログラムの基点となるディレクトリを dirname(FILE) で $library_path = dirname(__FILE__); include $library_path . '/foo/bar/hoge.php'; 2 のようにして使いまわすといいかも。 include_path と file_exists file_exists は include_path を使わずファイルの有無を返す関数なので、下記のようにすると file_exists は true なのに include できないという状況がありえる。 if(file_exists('foo/bar/hoge.php')){ // 基点となったファイルから相対パスで hoge.php を探す include 'foo/bar/hoge.php'; //include_path から相対パスで hoge.php を探す } これを成功させるには include_path に (カレントディレクトリ) . が含まれていなければならず、普 通は php.ini の初期設定でそのようになっているが、.htaccess 等を使って include_path を再設定(上 書き)する際は注意が必要。 大文字小文字 変数名の大文字小文字は区別される。 $hoge = 10; $Hoge = 20; echo $hoge; // 10 edho $Hoge; // 20 配列の添え字も同様。 $foo = array(); $foo['bar'] = 10; $foo['Bar'] = 20; echo $foo['bar']; // 10 echo $foo['Bar']; // 20 関数名の大文字小文字は区別されない。 function hoge() { return 10; } echo hoge(); // 10 echo Hoge(); // 10 クラスのときも関数と同様。 class foo { static function bar() { return 10; } } echo echo echo $obj echo foo::bar(); // 10 Foo::bar(); // 10 Foo::Bar(); // 10 = new fOO(); $obj->bAR(); // 10 値渡しと参照渡し 3 new について PHP4 のとき $Foo = &new Foo(); // 参照渡し $Foo = new Foo(); // 値渡し $Bar= $Foo; // 値渡し PHP5 のとき $Foo = new Foo(); // 参照渡し $Bar = $Foo; // 参照渡し $Bar = clone $Foo; // 値渡し PHP5 では new のデフォルトが参照渡しになったため、逆に値渡し(コピー)したい場合は clone を使う。 引数の参照渡し 普通は受け取る側で & で受け取ればよい。 <?php class Hoge { function changeValue(&$data) { $data = 'Hoge'; } } $data = 'Huga'; $Hoge = new Hoge(); $Hoge->changeValue($data); echo $data; // Hoge が出力される user_call_func_array() を使った場合は、送る側と受け取る側のどちらも & になっていなければ参照 渡しとならない。 <?php class Hoge { function changeValue(&$data) { $data = 'Hoge'; } } $data = 'Huga'; call_user_func_array(array('Hoge', 'changeValue'), array(&$data)); echo $data; // Hoge が出力される 戻り値の参照渡し <?php class Hoge { public $data = 'Huga'; function &getValue() { // A return $this->data; } } $Hoge = new Hoge(); $data = &$Hoge->getValue(); // B $data = 'Hoge'; echo $Hoge->getValue(); // Hoge が出力される 4 A と B に対し、& が付いたときのみ参照渡しとなる。 いずれが欠けても値渡しとなるので注意。 session.use_trans_sid cookie が使える環境では session.use_cookies = 1 としていれば cookie が利用できるが(ただしブラウザ側でも cookie に対応のこと)、携帯など cookie に対応していない場合に session.use_trans_sid = 1 とする方法がある。 これを設定すると HTML の A タグ等のリンク <a href="/foo.php">foo</a> に自動的に <a href="/foo.php?PHPSESSID=XXXXX">foo</a> session id が付加される。 ただし http から記述したリンクは外部パスとみなされ、session id が付加されないので注意。 <a href="http://foo.bar.com/foo.php">foo</a> また、当然ながら session start(auto start)しないと機能しない。 PHP Manual:セッション ID の受渡し http://jp2.php.net/manual/ja/session.idpassing.php mod_php と CGI のリダイレクト sample.php からのリダイレクトで header('Location: ' . $url); exit; とかした場合、$url が 1.http://foo.bar.com/hoge.html 2./hoge.html 3.hoge.html 5 2 のときの挙動が mod_php と CGI の php とで違ってくる。 mod_php のときは 1 も 2 も URL http://foo.bar.com/hoge.html にリダイレクトされるが、CGI のとき は 2 のときに URL は http://foo.bar.com/sample.php のまま、hoge.html の内容が表示される。 これは内部リダイレクトと呼ばれているみたいで、Location ヘッダ自体が出力されないらしい。 OKwave:相対 URL によるリダイレクト http://okwave.jp/qa/q2428571.html 一部のブラウザや docoom では相対 URL が NG みたいだが、絶対 URL ならすべての環境で OK と いうわけでもないらしい。 @IT:モバイル Web 開発に失敗しない鉄則 http://www.atmarkit.co.jp/fdotnet/aspnetmobile/aspnetmobile05/aspnetmobile05_02.html CGI の挙動の件は下記が詳しい。 ぐらめぬ・ぜぷつぇんのはてダ:cgi.force_redirect って何? http://d.hatena.ne.jp/msakamoto-sf/20080802/1217662203 split split() は『大文字小文字を区別しない正規表現により文字列を分割し、配列に格納する』なのだが、 正規表現にはまった。 $strs = split("¥s", $str); これで $str に格納された文字列中の空白文字により分割されると思ったが、実際には機能しない。 POSIX で空白文字は $strs = split("[ ¥t¥n¥r¥f¥v]", $str); というようになるようだ。 空白文字が連続していても 1 つの区切りとしたい場合は $strs = split("[ ¥t¥n¥r¥f¥v]+", $str); とすればいい。 正規表現を必要としない、例えば改行で分割されればよい、というのであれば explode を使ったほ うが高速。 6 $strs = explode("¥n", $str); 正規表現 - Wikipedia http://ja.wikipedia.org/wiki/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE preg と ereg 共に正規表現を扱う関数群。 preg のほうが速く動作するようなので、基本は preg で。 ・ereg は POSIX 拡張 ・preg は Perl 互換 POSIX 正規表現関数 http://jp2.php.net/manual/ja/ref.regex.php PCRE 関数 http://jp2.php.net/manual/ja/ref.pcre.php 動作確認に便利なサイト発見。 PHP の種:PREG ONLINE http://www.php-seed.net/preg/ mbstring 日本語を扱う場合に設定するものだが、いまいち各設定の関係がよくわからなかったので試して みた。 mbstring.language mbstring.internal_encoding neutral UTF-8 まず .language が neutral だと .internal_encoding の UTF-8 が効かない。 つづいて mbstring.language mbstring.internal_encoding mbstring.encoding_translation neutral UTF-8 On だと、HTTP 入力に対して自動的に .internal_encoding(内部エンコーディング)の設定に変換しよ うとする。 たとえば .encoding_translation が正常に機能する場合、EUC-JP の HTML フォームからポストされ てきたデータは $_POST['hoge']; 7 に格納されている状態で既に EUC-JP から .internal_encoding(内部エンコーディング)の UTF-8 に変換済みとなる。 が、やはり .language が neutral だと .internal_encoding が効かないため、結果的に .encoding_translation も機能しないことになる。 同様にプログラム内部で mb_convert_encoding() を使用し、auto を使っている場合、 $str = mb_convert_encoding($str, 'UTF-8', 'auto'); この auto も .internal_encoding(内部エンコーディング)が効かない状態だとうまく機能しない模 様。 auto ではなく直接、'EUC-JP, UTF-8' のように指定する分には OK らしい。 とりあえず mbstring.language Japanese じゃないといろいろはまる。 プログラムでセットする場合は mb_language('Japanese'); 配列に対する文字エンコーディングの一括変換 string mb_convert_encoding(str, to_encofing, from_encoding) となっており、str に array を渡してしまうと空っぽの array が返ってくる。 $str = array(' 古池や ',' 蛙飛び込む ',' 水の音 '); $str = mb_convert_encoding($str, 'UTF-8', 'auto'); print_r($str); // Array() 上記の mbstring 設定との絡みを考えてサンプルを作ってみる。 // mbstring.encoding_translation = Off を想定 mb_language('Japanese'); ini_set('mbstring.detect_order', 'auto'); ini_set('mbstring.http_input' , 'pass'); ini_set('mbstring.http_output' , 'pass'); ini_set('mbstring.internal_encoding', 'UTF-8'); ini_set('mbstring.script_encoding' , 'UTF-8'); ini_set('mbstring.substitute_character', 'none'); // ↓ euc-jp の form から空白文字区切りの文字列が post されてくるのを想定 $request = split("[ ¥t¥n¥r¥f¥v]+", $_POST['comment']); $request = mb_convert_variables('UTF-8', 'EUC-JP', $request) プロキシ経由かチェック 8 レンタルサーバで共有 SSL を利用可能とするコードを書く場合、クライアント∼共有 SSL 用プロ キシは HTTPS でも、共有 SSL 用プロキシ∼ Web サイトのあるサーバは内部で HTTP となってい る場合がほとんど。 クライアント − (https) − 共有 SSL 用プロキシ − (http) − Web サーバー そのため Web サーバー側で処理される $_SERVER['HTTPS'] で HTTPS かどうか判定できない。 xrea、coreserver では squid が使われていて if (isset($_SERVER['HTTP_VIA']) && isset($_SERVER['HTTP_X_FORWARDED_FOR'])) というような感じ。 sakura ではプロキシが何か調べてないが if (!isset($_SERVER['HTTP_VIA']) && isset($_SERVER['HTTP_X_FORWARDED_FOR'])) となる模様。 実際には変数にセットされている値もチェックしたほうがいいのかな。 eForm で画像認証を使いたい http://modxcms.com/forums/index.php?topic=32384.75;wap2 MySQL と client と文字化け 文字化けの仕組みは割愛して(汗)。 以前から気になっていたのは my.cnf にある [client] の設定。 [client] default-character-set=utf8 [mysql] default-character-set=utf8 [mysqld] default-character-set=utf8 となっている場合、[client]ってなんなのだろうか?ということ。 例えば MySQL が latin1 で、上記のように my.cnf の設定により utf8 になっているとする。 このとき PHP から MySQL に接続をかけると、[client] の設定に従い utf8 で接続することになるの では ... と思ったが、事実は違って latin1 での接続となる。 この [client] は libmysqlclient を使って mysqld サーバに接続をかけるときの話らしい。 で、libmysqlclient を使って接続をかけることができるのは PHP では mysqli_real_connect() で、mysqli は PHP5 から利用できる MySQL 改良版拡張モジュールだ。 要するに PHP4 の場合は使えない。 9 MySQL 改良版拡張モジュール http://jp.php.net/manual/ja/book.mysqli.php で、PHP5 だ っ た と し て、PEAR::DB で mysqli を 利 用 で き る が、コ ー ド を 読 む と 普 段 は mysql_connect() で接続し、SSL で接続する際は mysqli_real_connect() を使うようになっていた。 「mysqli を指定しているのに mysql_connect() を使ってる状態」になるので注意が必要。 多分、PEAR::MDB2 なら OK だと思われる。 まとめると PHP5 → mysqli → mysqli_real_connect() → libmysqlclient(my.cnf) → mysqld という接続のとき my.cnf の [client] の設定が効いてくることになる。 MySQL 初心者日記:libmysqlclient について http://nysql.g.hatena.ne.jp/py4s-tnk/20090329/1238341015 パフォーマンス改善 え∼ そうだったの? みたいなのもあって、かなり参考になった。 Selfkleptomaniac:PHP のパフォーマンス改善 (1) http://selfkleptomaniac.org/archives/43 Selfkleptomaniac:PHP のパフォーマンス改善 (2) http://selfkleptomaniac.org/archives/44 Selfkleptomaniac:PHP のパフォーマンス改善 (3) http://selfkleptomaniac.org/archives/45 高速化のための書き方 なるほど∼ Otaxa:PHP、チョイ高速化テクニック http://otaxa.com/blog/others/php-faster-technics/?utm_source=twitterfeed&utm_medium=twitter マジックメソッド クラスの中で使用する、アンダースコア 2 つではじまる名前の特殊関数。定められたタイミング で起動する。 マジックメソッド 説明 新たにオブジェクトが 生成される度に起動 __construct() 10 __destruct() 特定のオブジェクトへの全てのリファレンスが 削除された直後やオブジェクトが明示的に破棄 された直後、あるいはスクリプトの終了時に起 動 __call() アクセス不能メソッドをオブジェクトのコンテ キストで実行したときに起動 __callStatic() アクセス不能メソッドを静的コンテキストで実 行したときに起動 __get() アクセス不能プロパティからデータを読み込む 際に起動 __set() アクセス不能プロパティへデータを書き込む際 に起動 __isset() isset() あるいは empty() をアクセス不能プロパ ティに対して実行したときに起動 __unset() unset() をアクセス不能プロパティに対して実行 したときに起動 __sleep() serialize() によるシリアル化の前に起動 __wakeup() unserialize() によるアンシリアル化の前に起動 __toString() クラスが文字列に変換される際に起動 __invoke() スクリプトがオブジェクトを関数としてコール しようとした際に起動 __set_state() PHP5.1.0 以降で var_export() によってエクス ポートされたクラスのためにコール __clone() オブジェクトが clone キーワードでコピーされ る際に起動 PHP Manual:マジックメソッド http://jp2.php.net/manual/ja/language.oop5.magic.php flush() と ob_flush() と ob_start() のネスト php の出力バッファを任意のタイミングで吐き出すのが ob_flush() で、web サーバーの出力バッ ファは flush() らしい。 よって順序としては <?php for ($i=0; $i < 1000; $i++) { echo $i . "<br>¥n"; ob_flush(); flush(); } 11 で、逐次出力されていく。 ob_start() してる間の echo とかの出力がバッファに溜まって、途中で ob_flush()、flush() しなければ プログラムが終了したときに出力されるが、既に ob_start() しているときに更に ob_start() みたいな ネストすることもできる。 この場合ネストは先入れ後出しとなり、ob_end_flush() でネストの深いところから総出力するには while(ob_get_level()) ob_end_flush(); flush(); となる。 12