日記
BMediaNode: PHPプログラマの技量を知りたいとき (17:15)Edit

ちなみに私がPHPプログラマの技量を知りたい時には、ファイル数・構成は無制限で以下のような仕様のスクリプトを書いてもらいます。

で書かれている仕様のスクリプトを試しに書いてみた。所要時間は見直しを含めて30分くらいか。エラー処理に関する仕様は多少適当というか、解釈が違っているかも。

index.php

<?php
define('ACTION_URL', './index.php');
define('INTERNAL_ENCODING', 'UTF-8');
mb_internal_encoding(INTERNAL_ENCODING);
set_include_path('.');
main();
function main()
{
header('content-type: text/html; charset=' . INTERNAL_ENCODING);
switch ($_SERVER['REQUEST_METHOD']) {
case 'POST':
$zip = importZip();
$errorMsg = validateZip($zip);
if ($errorMsg) {
showInputForm($zip, $errorMsg);
} else {
if (isset($_POST['btnNext'])) {
showCheckForm($zip);
} elseif (isset($_POST['btnSave'])) {
saveZip($zip);
showResultPage($zip);
} else {
showInputForm($zip);
}
}
break;
default:
showInputForm();
break;
}
die;
}
function importZip()
{
$zip = isset($_POST['zip']) ? $_POST['zip'] : '';
$zip = trim(mb_convert_kana($zip, 'KVas'));
$zip = str_replace('-', '', $zip);
return $zip;
}
function validateZip($zip)
{
if ($zip == '') {return '入力されていません';}
if (!preg_match('|^[0-9]{7}$|', $zip)) {return '入力内容が正しくありません';}
return NULL;
}
function saveZip($zip)
{
// zipを保存
}
function showInputForm($zip = '', $errorMsg = NULL)
{
$actionUrl = ACTION_URL;
include('tmpl/form.tmpl');
}
function showCheckForm($zip = '')
{
$actionUrl = ACTION_URL;
include('tmpl/check.tmpl');
}
function showResultPage($zip = '')
{
$actionUrl = ACTION_URL;
include('tmpl/result.tmpl');
}
function h($str)
{
return htmlspecialchars($str);
}
?>

tmpl/form.tmpl

<form method="POST" action="<?=h($actionUrl) ?>">
郵便番号: <input type="text" name="zip" value="<?=h($zip) ?>" size="10">
※半角数値7桁で入力してください
<br>
<?php if (isset($errorMsg)) : ?>
<p><?=h($errorMsg) ?></p>
<?php endif ?>
<input type="submit" name="btnNext" value="次へ">
</form>

tmpl/check.tmpl

<form method="POST" action="<?=h($actionUrl) ?>">
<input type="hidden" name="zip" value="<?=h($zip) ?>">
郵便番号: <?=substr($zip, 0, 3) . '-' . substr($zip, 3) ?>
<br>
<p>上記でよろしいですか?</p>
<input type="submit" name="btnBack" value="戻る">
<input type="submit" name="btnSave" value="次へ">
</form>

tmpl/result.tmpl

入力された郵便番号は <?=substr($zip, 0, 3) . '-' . substr($zip, 3) ?>です。

HTMLヘッダ・フッタとかは省略。まあ必要ならば適当にテンプレートで補えばいいし。ソースの文字コードはUTF-8。スクリプトの頭で強制的にmb_internal_encodingをセットするのは、いまいち設定がどうなっているかわからないサーバーで動かすための生活の知恵。

って感じで、俺ならOOPは使わずに書くなー。というか、PHPの利点はこの程度のコードならば(1回こっきりスクラッチから書くならば)こんな感じで手軽に書けるところだと思うんだけど。

まあこういうコードしか書けない(クラスを使ったコードが理解できない&PEAR等を使いこなせない)ってんじゃ大規模なアプリケーションを書くときについて行けなくなるだろうけど。

というわけで、暇なPHPプログラマの方、この仕様で自分が書くならこう書く、というサンプルを書いてみませんか。ちなみにクラスをネームスペース代わり程度に使ったサンプルも試しに書いてみた。

index2.php

<?php
define('INTERNAL_ENCODING', 'UTF-8');
mb_internal_encoding(INTERNAL_ENCODING);
set_include_path('.');
main();
function main()
{
header('content-type: text/html; charset=' . INTERNAL_ENCODING);
$form =& new ZipForm();
$form->execute();
}
class ZipForm
{
var $_actionUrl;
var $_zip;
var $_errorMsg;
var $_formMode;
function ZipForm($options = array())
{
$this->__construct($options);
}
function __construct($options = array())
{
$this->_actionUrl = isset($options['actionUrl']) ?
$options['actionUrl'] : $_SERVER['PHP_SELF'];
$this->_zip = '';
$this->_errorMsg = NULL;
$this->_formMode = 'form';
}
function getZip()
{
return $this->_zip;
}
function getErrorMsg()
{
return $this->_errorMsg;
}
function getMode()
{
return $this->_formMode;
}
function execute()
{
switch ($_SERVER['REQUEST_METHOD']) {
case 'POST':
$this->import();
if ($this->isValid()) {
switch ($this->getMode()) {
case 'check':
$this->showCheckForm();
break;
case 'save':
$this->save();
$this->showResultPage();
break;
case 'input':
default:
$this->showInputForm();
break;
}
} else {
$this->showInputForm();
}
break;
default:
$this->showInputForm();
break;
}
}
function import()
{
$this->_zip = isset($_POST['zip']) ? $_POST['zip'] : '';
$this->_zip = trim(mb_convert_kana($this->_zip, 'KVas'));
$this->_zip = str_replace('-', '', $this->_zip);
if (isset($_POST['btnNext'])) {
$this->_formMode = 'check';
} elseif (isset($_POST['btnSave'])) {
$this->_formMode = 'save';
} elseif (isset($_POST['btnBack'])) {
$this->_formMode = 'input';
} else {
$this->_formMode = 'input';
}
}
function isValid()
{
$this->_errorMsg = NULL;
if ($this->_zip == '') {
$this->_errorMsg = '入力されていません';
} elseif (!preg_match('|^[0-9]{7}$|', $this->_zip)) {
$this->_errorMsg = '入力内容が正しくありません';
}
return !isset($this->_errorMsg);
}
function showInputForm()
{
$actionUrl = $this->_actionUrl;
$zip = $this->_zip;
$errorMsg = $this->_errorMsg;
include('tmpl/form.tmpl');
}
function showCheckForm()
{
$actionUrl = $this->_actionUrl;
$zip = $this->_zip;
$errorMsg = $this->_errorMsg;
include('tmpl/check.tmpl');
}
function showResultPage()
{
$actionUrl = $this->_actionUrl;
$zip = $this->_zip;
$errorMsg = $this->_errorMsg;
include('tmpl/result.tmpl');
}
function save()
{
// zipを保存するコードをここに書く
}
}
function h($str)
{
return htmlspecialchars($str);
}
?>

元の関数型コードをできるだけ流用しようとしたせいで、設計ポリシーがなんとも中途半端な感じだね。execute相当の処理を外出しにするかクラス内部で完結させるか迷った結果、キメラのようなインターフェースになっている。

もしちゃんと作るならば、表示系はクラスの中に含ませずに、クラス自体はDataObject的に作るだろうな。で、表示系は外部コード+テンプレートライブラリにお任せって感じで。

HTML_QuickForm+Smartyを使ったサンプルとかも書いてみようかと思ったけど、最近使ってないんでパス。最近は自前のフレームワークの中に安住してしまっているんで、他のフレームワークを使うのがだるいんだよなー。

Published At2005-04-19 00:00Updated At2005-04-19 00:00