Home > アーカイブ > 2008-04
2008-04
Podcastで聞くPHP
- 2008-04-28 (月)
- PHP
先日ipod Touchを買いました*1。
買う前は、nanoやclassicとで迷っていた(特に価格面で)のですが、実際買ってみると独特のUIや液晶の大きさなど、とても気に入ってます。
iPodならPodcast、という事でPHPに関するPodcastを探してみました。
そこで見つけたのが、PHP Podcastsです。
PHPに関するPodcastと言えば、php|architect’s C7YやZendのPHP Abstractなどが有名ですが、PHP Podcastsはこれらのaggregatorとなっているので、ここをiTunesに購読しておけば、様々なPodcastをチェックすることができます。
PHP Podcastsでは以下のようなPodcastをアグリゲートしているようです。
- P3 (php|architect’s PHP Podcast)
- PHP Abstract
- The Show for CakePHP
- Drupal Podcast
- KILLER PHP
- Official phpBB Podcast
- WebDevRadio
- The WordPress Podcast
- The ZendCon Sessions Podcast
全て英語なのが寂しいところですが、本場の雰囲気を感じられて面白いです。(内容はちんぷんかんぷんですが:-P)
日本でも誰かやりませんか? > Podcast
- コメント (Close): 0
- トラックバック: 0
PHP 配列を回すならforかforeachか
- 2008-04-25 (金)
- PHP
今日、社内で「PHPの配列をループで回すのにforを使うか、foreachを使うか」という話が面白かったので、メモ。
ここでいう配列はキーが数字で、0からの連番であることを想定してます。(キーが数字以外や連番で無い場合は、foreachを使います。)
例えば↓のようにDBテーブルからレコードを読み込んだ内容が入ってる場合、$listをループで回すならforとforeachのどちらを使うべきかという話です。
<?php $list = array(); $list[] = array('id' => 1, 'name' => 'hoge'); $list[] = array('id' => 2, 'name' => 'foo'); $list[] = array('id' => 3, 'name' => 'bar'); ?>
for文派
<?php for ($i = 0 ; $i < count($list); $i++) { echo $list[$i]['id'] . PHP_EOL; echo $list[$i]['name'] . PHP_EOL; } ?>
1. ループ内でデータが直感的に参照できる
$listが2次元配列になっているのが分かっているので、直感的にデータへ参照できる。
2. 誰でも知っている構文である
プログラムを知っていれば、誰でも分かる。(foreachに比べると)
3. 参照する変数が変わらない
まあ1.とほぼ同じですが、$listのデータを参照・操作したいので、$list変数へ参照した方が分かりやすい。
=> foreachだとループ内で参照する変数が変わるのが直感的で無い。
foreach派
<?php foreach ($list as $id => $rec) { echo $id . PHP_EOL; echo $rec['name'] . PHP_EOL; } ?>
1. 添え字が数字だろうが、何だろうが要素を順番に参照できる
(PHPでは全てもともと連想配列ですが)リストかハッシュかを意識する必要が無い。
さらに言うとIteratorをimplementしていれば、どのようなデータ構造でもforeachでループを回せる。
2. 参照すべき変数を限定できる
上の例でいうと、ループ内では$listを意識する必要はなく、$idもしくは$recさえ知っておけば要素へ参照できる。
またループ内では$listがどういう構造なのかも知る必要がない。
3. 要素の内容を表す変数名で参照できる
配列は$listだが、添え字を$id・要素を$recと、内容を表す変数が指定できるので、分かりやすい。
おまけ. 若干早い
以前取ったベンチでは、foreach()の方が早かった。ただ配列の要素数が数十程度では大した差にはならないのでそれほど神経質にならなくても良い。
PHPではforeachで
個人的には連想配列しか無いPHPでは、配列は単純にforeachで回すというルールで良いと思います。
私自身はforeach派なのですが、for文派の1や3のようにあくまで配列をイメージして各要素に参照したいというのを利点として挙げていたのが新鮮でした。(私は$list[$i][‘name’]と参照するのが冗長に感じていたので。)
forかforeachか、みなさんはどちらでしょう?
追記(2008/04/26):
皆さんコメントありがとうございます!確認した限りでは、全員foreach派で、for文派はいませんでした;-)。やはりPHPではforeachを使うのが一般的のようです。
以下、foreach派のコメントを。
- rytich foreach派
- @shimooka iteratorのように配列の要素数を意識しなくていいのが楽です>foreach
- @lllnorikolll 私もforeachが多いです。
- @junya バグの入る余地が少ないからforeachのほうが好み
- @nazo 全要素に対して何かするならforeach、指定回数何かするならfor
- @sonkm3 for よりは foreach の方が好きだな。インデックス用の変数ってうっかりしやすいから。。。
- id:creazynet 今はほぼforeachだけですね。for→foreachを使う様になった時がjava脳→php脳に変わった瞬間だった気がします。
- id:Kiske 普段はforeach、処理データ大きいときはwhile使ってる / while(list($key, $value) = each($array)){…}
- id:heavenshell ほぼ foreach かなぁ。
関連エントリ
- コメント (Close): 12
- トラックバック: 4
rsyncの–deleteでファイルが削除されない
- 2008-04-24 (木)
- unix
rsyncで以前困ったこと。
–deleteを付けて同期しているのに、同期元で削除したファイルがなぜか同期先で消えない現象が発生。
結局理由は、同期元のパスに*(アスタリスク)を付けていたのが原因だった。
ディレクトリ構成は↓な感じ。
$ find ./ ./src/ ./src/a ./des ./des/a ./des/b
bはdes/にはあるが、src/には無いので–delete付けると、消えるはず。
$ rsync -avz –delete src/* des/
$ find ./
./src/
./src/a
./des
./des/a
./des/b <--- 消えてない。。。
[/code]
アスタリスク無しで実行すればok。
$ rsync -avz –delete src/ des/
$ find ./
./src/
./src/a
./des
./des/a
<--- 消えた!
[/code]
ちなみにsrc/以下のサブディレクトリについては、[*]付けてもokでした。[*]を指定したディレクトリでは、ディレクトリエントリは見ないのかな。
rsyncでディレクトリを指定する際は、末尾に[/]を付けるつけないで挙動が変わるから、安全のために[*]を付けていたのが、逆に仇となったという話でした。パラメータはキチンと把握しておこう。
- コメント (Close): 1
- トラックバック: 0
CakePHP Modelに関する6つの誤解
CakePHPのModelはActiveRecordライクなDBアクセス方法を提供しており、さらにアソシエーションを設定することにより複数テーブルの値を同時に操作できるなど、DB操作に対するインターフェイスが数多くあります。
ただ「手軽にDB操作ができる」という印象が先行しているゆえ誤解を招くことがあるようです。
1. クラス名に対応したテーブルしか操作できない
Modelのクラス名とテーブルを自動でマッピングするのはフレームワークのいわば便利機能です。デフォルトでそのような動作をするだけで、容易に変更することができます。
Model#$useTableにテーブル名を指定すれば任意のテーブルを操作できます。
<?php class Foo extends AppModel { public $useTable = 't_user'; // t_userテーブル } ?>
2. DBを使わないといけない(DB操作が無いと使えない)
DB操作が強調されるので陥りがちですが、DBを使わないModelも作成できます。例えばバリデーションだけを行うModelやDB操作を行わないビジネスロジックを実装したModelなどももちろんokです(というかビジネスロジックを実装するもの)。
DB操作を行わないModelでは、Model#$useTableにfalseを入れておけば良いです。(nullではなく、falseです)
<?php class Foo extends AppModel { public $useTable = false; // テーブルに対応させない } ?>
3. ステートレスである
find()/findAll()等ではarrayを返すので、何となくステートレスな感じがしたりしますが、実はModelではしっかり情報を保持しています。
メソッド終了時にリセットされる値も一部ありますが、Model#set()などで設定した値はそのまま保持しています。ループの中で複数レコードを登録する際は注意する必要があります。
保持している値についてはModel#create()を呼ぶことにより初期化(クリア)できます。
<?php foreach ($list as $data) { $this->Foo->create(); // クリアしておく $this->Foo->save($data); } ?>
4. bakeで生成したModelは変更しない(できない)
bakeでバリデーションやアソシエーションを設定しておくと、生成されるModelではインスタンス変数に様々な値が記述されます。
単純なDB操作のみならばこのままModelのソースを触ることなく開発できますが、複雑なDB操作やビジネスロジックなどを実装する場合は、臆することなくModelにガンガン追加していきましょう。
5. DBのリレーションを全てアソシエーションでも設定する
アソシエーションはとても便利なものですが、上手く利用しないと思わぬSQLが発行され、パフォーマンスに影響が出ます。テーブル同士に外部整合性制約を付けてリレーションしているからと言って、必ずアソシエーションを設定する必要はありません。
はじめからシステムで不要と思われるアソシエーションについては設定しないというのも手です。
いっそ最低限のアソシエーションのみを設定しておき、後は用途に応じてModel#bind()/bindModel()する方が良いかもしれません。
特にModel#$hasManyを設定していると芋づる式に数多くのSQLが発行される場合があるので、注意しましょう。
6. DAOである
DAOのように振る舞うメソッドが多数ありますが、実際にDBへアクセスするのはDataSourceを継承したdboクラスであり、Modelではありません。
ModelをDAOとしか認識していないと、ビジネスロジックはControllerに実装することになり、Controllerが肥大していくことになります。
もちろんModelをDAOのように使うこともできますが、あくまでModelですので、ビジネスロジックはControllerでなくModelで実装して、Controllerへはそのインターフェイスを提供するようにしましょう。
CakeのModelはMVCのModel
しつこく書いてますが、CakeのModelもいわゆるMVCのModelと同じです。DB機能ばかりが強調されていますが、それに捕らわれることなく本来のModelとして活用しましょう。
- コメント (Close): 1
- トラックバック: 1
CakePHP 1.2で携帯用ビューを表示する
CakePHP1.2ではCakePHP 携帯用ビューを表示するで利用していたwebservicesの機能が無くなります。
1.2-betaでRouting.webservicesをonにすると以下のようなメッセージが表示されます。
Deprecated: webservices routes are deprecated and will not be supported in future versions. Use Router::parseExtensions() instead.
The prefix automagic in CakePHP routingで紹介されているように、1.2からはwebservicesに替わりprefixをURLルーティングで使用するようです。
そこで実際にどのように使用するかを試してみました。
1. URLルーティングでprefixを設定する
Router::connect()の第2引数ではパラメータを連想配列で設定できるのですが、そこに’prefix’というキーで値を設定しておくと、対象URLにアクセスがあればこの機能が有効となります。
下記の例では[/m/foo/bar]へアクセスがあると、prefix=mobileが有効となります。
[app/config/routes.php]
Router::connect('/m/:controller/:action', array('prefix' => 'mobile'))
2. prefix用アクションを作成する
prefixが有効な状態だと、アクションとして[prefix + _ + action]が呼ばれるので、アクションを実装します。
1. の設定で[/m/foo/bar]へアクセスされると、prefix=’mobile’が有効となるので、FooController#mobile_bar()がアクションとして呼ばれます。
[app/controllers/foo_controller.php]
<?php class FooController extends AppController { public function mobile_bar() { // 通常のアクションを実装 } } ?>
3. prefix用ビューを作成する
2.で実装したアクション同様にビューテンプレートを作成します。
これは通常どおり2.で作成したアクションに対応するビューテンプレートを作成するだけです。
注意点は$html->link()などでURLを指定する際は、アクションにprefixが付いたアクション(mobile_bar)を指定するという事です。下の例なら「/m/foo/bar」がURLとして出力されます。
[app/views/foo/mobile_bar.ctp]
<?php echo $html->link('link', array('controller' => 'foo', 'action' => 'mobile_bar')); ?>
△prefix用Component/Helperが読まれない
携帯電話では入出力文字エンコーディングを変換する事が多いのですが、webservicesを使用すると読み込まれるComponent/Helperで実装していました。
今のところprefixではこの機能が無いようなので、Controller#beforeFilter()/afterFilter()等で自前で実装する必要がありそうです。
そのリクエストで設定されているprefixはController#$params[‘prefix’]で確認できます。(@see 1.2 の WEBSERVICES パラメータ)
○prefix用アクションは直接呼ばれない
prefixに設定したアクションは直接呼ぶことができず、prefixで設定したURLでないとアクセスできません。
つまり1.のような設定の場合、[/foo/mobile_bar]へアクセスしてもprivate methodとして扱われてエラーとなります。
これによりprefixが設定されず、prefixアクション(mobile_bar)が呼ばれるのを防ぎます。
このあたりの挙動はRouting.adminと同じですね。:-D
webservicesは中々便利な機能だったので無くなるのは残念ですが、代替機能があるのは嬉しいことです。
- コメント (Close): 0
- トラックバック: 3
CakePHP DboSourceをPHP5らしく使う
CakePHPではDBアクセスは通常Modelを介して行うので、直接DboSourceを利用する事は無さそうですが、SQL文を自分で構築する際など、意外と使う機会があります。
DboSourceは、通常以下のよう使用します。
<?php // $hogeをエスケープ $db =& ConnectionManager::getDataSource($this->useDbConfig); $db->value($hoge); ?>
もちろんこれでも問題無いのですが、やや冗長な感じもあります。そこでPHP5で以下のように書いてみました。
<?php ConnectionManager::getDataSource($this->useDbConfig)->value($hoge); ?>
1文にまとまりました。ただ、まだ冗長なので、これをAppModelでまとめてみます。
<?php class AppModel extends Model { public function getDbo() { return ConnectionManager::getDataSource($this->useDbConfig); } } ?>
使う際はこうなります。
<?php // Modelなら $this->getDbo()->value($hoge); // Controllerなら $this->Foo->getDbo()->value($hoge); ?>
スッキリした書き方になりました;-)
そろそろPHP5も普及しつつあるので、CakePHPももっとPHP5らしい書き方に移行したいな、という話でした。
- コメント (Close): 0
- トラックバック: 1
CakePHP FormHelper#datetime()で年月日表示を変える
CakePHP1.2で追加されたFormHelperには日時をプルダウンメニューで選択する機能があります。
<?php echo $form->datetime('hoge', 'YMD', 'NONE'); ?>
これで年月日を選択できるのですが、デフォルトだと↓のように月が英語表現で表示されます。
そこで月を数字表現に変更する方法です。
datetimeメソッドはFormHelper#$optionsの値をプルダウンで表示するリストに使用します。(値が無ければデフォルト値を使用)よってこれを書き換えれば任意の値をリストに表示できます。
<?php // 月を数字へ $form->options['month'] = array(); for ($i = 1 ; $i <= 12 ; $i++) { $form->options['month'][$i] = sprintf("%02d", $i); } ?> <?php echo $form->datetime('hoge', 'YMD', 'NONE'); ?>
これで以下のようになります。
FormHelper#$optionsでは月の他に様々なリストを指定できるので、年を和暦表現する、任意の日のみ選択対象にするなど変更できます。
■指定できるリスト
$options[‘year’] | 年 |
$options[‘month’] | 月 |
$options[‘day’] | 日 |
$options[‘hour’] | 時(12時間表現) |
$options[‘hour24’] | 時(24時間表現) |
$options[‘minute’] | 分 |
$options[‘second’] | 秒 |
$options[‘meridian’] | 午前・午後 |
日時表現としては、FormHelper#time()、FormHelper#input()もありますが、これらも内部的には同じロジックを共有しているので、同じように指定ができます。
- コメント (Close): 0
- トラックバック: 1
Home > アーカイブ > 2008-04
- 検索
- フィード
- メタ情報