カテゴリー別アーカイブ: PHP

PHP de オブジェクト指向 Part.2

PHP de オブジェクト指向part.2

この間のクラスに機能を追加してみる。

class SimpleDataObject
追記・変更

protected $_mask;

public function __construct($id){
$_mask[] = ‘id’;
foreach(get_object_vars($this) as $key => $val){
if(strpos($key, ‘_’)===0) $this->_mask[] = $key;
}
$this->id = $id;
}

public function getColumns(){
$ret = array();
foreach(get_object_vars($this) as $key => $val){
if(in_array($key, $this->_mask)) continue;
$ret[] = $key;
}
return $ret;
}

public function setByArray($array){
foreach($array as $key => $val){
try{
$this->set($key, $val);
}catch(Exception $e){
throw new Exception(‘[‘.__FUNCTION__.’]エラー:’.$e->getMessage());
}
}
return true;
}

で、前回作ったEstimateDataObjectを使って

$obj = new EstimateDataObject(1);
$cols = $obj->getColumns();
$sql = ‘SELECT ‘.implode(‘,’, $cols).’ FROM Estimates WHERE id=’.$obj->get(‘id’).’;’;
$res = mysql_query($sql);
$row = mysql_fetch_assoc($res);
$obj->setByArray($row);

こんな事をすると、EstimateDataObjectで定義した変数を列挙したSQL文を作って$objに読み込むことが出来る。
で、これを更新保存するには、

$obj->set(‘name’, $_GET[‘name’]);
$sql = ‘UPDATE Estimates SET’;
foreach($cols as $col){
$sql .= ‘ '.$col.'=’.$obj->get($col).’,’;
}
$sql = rtrim($sql, ‘,’);
$sql .= ‘ WHERE id=’.$obj->get(‘id’);
mysql_query($sql);

みたいなことで出来る。
EstimateDataObjectだけでなく、SimpleDataObjectを継承してプロパティを増やしたクラスもこのコードで対応できたりする。
便利便利

(92)

カテゴリー: LAMP[Linux, Apache, MySQL, PHP], PHP | コメントをどうぞ

PHP de オブジェクト指向機能

PHPのオブジェクト指向機能でシンプルな機能実装をする。

class SimpleDataObject{
protected $id;

public function __construct($id){
$this->id = $id;
}

public function set($name, $val){
if(property_exists($this, $name)) $this->{$name} = $val;
else throw new Exception(‘[‘.get_class($this).’]の定義されていないプロパティ[‘.$name.’]にアクセスしました’);
return true;
}

public function get($name){
if(property_exists($this, $name)) return $this->{$name};
else throw new Exception(‘[‘.get_class($this).’]の定義されていないプロパティ[‘.$name.’]にアクセスしました’);
return false;
}

public function __set($key, $val){
throw new Exception(‘[‘.get_class($this).’]の定義されていないプロパティ[‘.$name.’]にアクセスしました’);
}

public function __get($key){
throw new Exception(‘[‘.get_class($this).’]の定義されていないプロパティ[‘.$name.’]にアクセスしました’);
}

}

みたいなクラスを作る。
何のことはない、プロパティを保存してset/getで入出力するだけ。 その上、プロパティはidだけ。
これじゃ役に立たないが、継承して

class EstimateDataObject extends SimpleDataObject{
protected $name, $staff_code, $date;
}

のようにすると、parentのset/get機能で、こちらで定義したname/staff_code/dateを操作できる様になる。

親クラスに機能を追加してみる。

public function format($format){
$str = $format;
foreach(get_object_vars($this) as $key => $val){
$str = preg_replace(‘/%’.strtoupper($key).’%/’, $val, $str);
}
return $str;
}

これで、format(“あなたのIDは%ID%です”)とか流すと、「あなたのIDは1です」みたいな挙動をしてくれる。
get_object_varsは、対象オブジェクトのプロパティを列挙するので、EstimateDataObjectでは、%NAME%, %STAFF_CODE%, %DATE%も置換できる様になっている。
同じように、get_object_varsをうまく使うことで、基本クラスの単純な機能で、継承先の機能を回すことが出来る。

(89)

カテゴリー: LAMP[Linux, Apache, MySQL, PHP], PHP | コメントをどうぞ

PHP 関数がどこから呼ばれたか調べたり & PHP定数

 PHPで共有ファンクションを使っているけど、それがどこから呼ばれているか知らなきゃならないことがある。
 こういうときに利用できる関数がdebug_backtrace()というファンクション。
 PHPでFatalエラーが出たときとかに呼び出し関係を表示したり出来るのはこの仕組みが働いている。
var_dump(debug_backtrace());
とか埋め込んでおくと、その関数が呼ばれたときに、呼び出し関係と各要素のダンプがみられる。

あまりスマートではないけど、ある関数で、特定のコードから呼び出されたら処理を変更したいって言うことがあるが
$backtrace = debug_backtrace();
if($backtrace[2][‘args’][0][‘logic_file’]==’parts/stockman.php’)
の様にして、バックトレースの要素を使って分岐すると言うことも出来る。

PHPの便利な定数。
PHPには便利な変数($_SERVER等)があってよく使われているけど、定数もいくらかそろっていて、これがデバッグ向けの物がほとんどなので、debugネタのついでにメモ。
__LINE__ 行番号。 「__LINE__.’で問題が発生しました’」みたいに例外を投げてみたり。
__FILE__ ファイルのフルパスとファイル名。 変数からも取得できるけどこっちの方が書きやすい。
__DIR__ ファイルの存在するディレクトリ。 dirname(__FILE__)と同義。
__FUNCTION__ 現在の関数名。
__CLASS__ 現在のクラス名。 継承した時に、継承元で定義してある__CLASS__を使ったメソッドを、継承先で呼び出しても継承元のクラス名が戻ってくる点に注意(継承先でも同じメソッドを定義して__CLASS__を呼んでやれば、継承先のクラス名がとれる) これに対して、get_class($this)を呼ぶと、継承先で呼び出せば継承先のクラス名が戻ってくる(まぁ、インスタンスの名前だから当たり前だが)
__METHOD__ 現在の(クラス)メソッド名。
__NAMESPACE__ 現在の名前空間。 名前空間が実装されたのが最近なんで使ったことがない。

(3192)

カテゴリー: LAMP[Linux, Apache, MySQL, PHP], PHP | コメントをどうぞ

PHPとMySQLと文字コードと

 最近の流れとして、文字コードと言えばUTF8って感じが強い(携帯などではSJISもあるけど)
 しかしながら、CentOSや海外から拾ったコンパイル済みPHPの従来型MySQL関数って、コネクト時のクライアントエンコーディングがlatin1になっている。
 この値は、mbstringとか色々変えても変わらず、自前でビルドしないとダメっぽい。
 他方、MySQLサーバではmy.cnfに

[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci

等と入れてやるとUTF8で回るし、個別にデータベースやテーブルを作るときに指定してやることも出来る(現在のMySQLではdefault-character-setは推奨外) コマンドラインのmysqlもmy.cnfに

[mysql]
default-character-set=utf8

とかすれば、UTF8で繋がる。
 それでも、PHPクライアントでmysql_connectして、mysql_client_encodingで引っ張るとlatin1になるし、SHOW VARIABLESクエリの戻り値もクライアントやリザルトはlatin1になってしまう。
 このため、最近のMySQLとPHP(5.2.3以降)の組み合わせではmysql_set_charsetと言う関数を使ってクライアントのエンコーディングを設定してやることが出来る(古いバージョンでは、SET NAMESクエリを発行して変更できるが、サニタイズ関連の動作が期待と異なる事になったり、タイムアウトしたDB接続を自動再接続したときにエンコーディングが元に戻る様だ)
 しかし、実際の所は、このあたりの設定をせずともPHPから処理する限りは、UTF8の文字列を普通にDBに格納して取得も出来てしまう。 これは、エンコーディング設定が同じなら同じ方法で文字列を化けさせているから、化けた文字列を格納しても、取り出し時に逆処理で戻してしまい、外見上は問題なく動作してしまっているのだ。
これをデータベースマネージャなどでテーブル表示すると化け化けの文字列であるから、管理コマンドや、別のアプリケーションからDBを参照したときに問題が起きるし、検索処理や関数などで予想外の動作をする可能性もあるので、エンコーディング設定はしっかり行っておかなければならない。

 my.cnfの[mysqld]でskip-character-set-client-handshakeを設定してやると、サーバの標準キャラクタセットをクライアント値と同期しないので、mbstring.internal_encodingをutf8にしたPHPとutf8設定のMySQLの組み合わせでutf8で格納されて、データベースマネージャなどでもちゃんと表示できるので、この方法を示しているページもあるが、この状態でもmysql_client_encodingはlatin1で、SHOW VARIABLES結果はutf8設定というおかしな状態になるので、これも予想外の動作をする可能性があるわけで、正しく動作させたければ、毎回mysql_set_charsetを実行するか、ソースからPHPをビルドして、標準エンコーディングをutf8にするなどした方が良いと思う。
 また、skip-character-set-client-handshake設定してしまうと、[mysql]のdefault-character-setと整合を取らなくなるので注意が必要(例えば、mysqlをdefault-character-set=ujisで動かしてると、mysqlコマンドで接続した段階ではクライアントがujisで、サーバはutf8クライアントと認識しているのでキャラクタセットの齟齬で文字化けが生じる)

(467)

カテゴリー: LAMP[Linux, Apache, MySQL, PHP], PHP | コメントをどうぞ

PHP設定2

  • PHPのセッション時間設定とか
    php.iniの設定ディレクティブ

    session.cookie_lifetime=秒数

    で、デフォルトのセッションクッキークライアント生存時間を設定している。
    初期値は0で、ブラウザが終了するまで有効。
    しかし、この設定でも長時間放置しておくとセッションが切れることがあるが、これは、サーバ側でセッションファイルが処分されるのが原因で、こちらは

    session.gc_maxlifetime=秒数

    と言うディレクティブで設定されていて、デフォルトが24分なので、これを1日とかに延ばしてしまえばOK。
    上の設定をしてもphpMyAdminが切れるのは、phpMyAdminのconfig.inc.phpの設定

    $cfg[‘LoginCookieValidity’] = ‘秒数‘;

    この値を設定する必要がある。

(178)

カテゴリー: LAMP[Linux, Apache, MySQL, PHP], PHP | コメントをどうぞ

応用コマンド1・PHP設定1

  • 現在のディレクトリ以下で探索語を含むファイルを探す。

find . -type f -print | xargs grep 探索語 /dev/null

  • PHP:DocumentRootより上のファイルのfopenに失敗する。

ウェブアプリがDocumentRootより上にあるファイルを読む場合に、php.iniの設定ディレクティブopen_base_dirに追記しておかないと、fopenがI/O errorになる。 .htaccessでphp_admin_valueで設定しても良い。

open_base_dir = 参照したいディレクトリ
(:区切りで列挙)

(45)

カテゴリー: LAMP[Linux, Apache, MySQL, PHP], PHP | コメントをどうぞ