2010-05-20

phpMyAdmin: エクスポート時にデフォルトでストアドプロシージャをエクスポート

phpMyAdminはデータのエクスポート時にストアドプロシージャがデフォルトでエクスポートされないようになっていて、 先日それに気づかずにエクスポート→再インポートしてストアドプロシージャを消してしまったので、デフォルトでストアドプロシージャをエクスポートする方法を調べていました。

ネット上に情報がなかったのでソースコードを調べたところphpMyAdminの設定ファイルに設定を少し書くだけでよかったようで、config.inc.phpに

$cfg['Export']['sql_procedure_function'] = true;

を追加することでエクスポート画面の「CREATE PROCEDURE / FUNCTION / EVENT を追加」のチェックボックスに初めからチェックが入るようになり、ストアドプロシージャもデフォルトでエクスポートできるようになりました。

2010-05-18

動的言語は引数チェックが面倒

例えばPHPで

  1. PHPのImage関数のラッパークラスをつくる必要がある
  2. imageline()関数をラップして線を引くメソッドをつくる必要がある
  3. 線を引くメソッドはdrawLine(int $x1, int $y1, int $x2, int $y2, int $color)としたい
  4. drawLine(Point $p1, Point $p2, int $color)ともできるようにしたい (Pointはxとyをフィールドとして持つクラス)

と考えたとき、もし仮にPHPにオーバーロード(PHP: オーバーロード - Manualじゃなく一般的な意味でのオーバーロード)があればdrawLine()は

class Image
{
  protected $id; // 画像リソースID

// コンストラクタ等省略...

  public function drawLine($x1, $y1, $x2, $y2, $color)
  {
    return imageline($this->id, $x1, $y1, $x2, $y2, $color);
  }
  public function drawLine($p1, $p2, $color)
  {
    return imageline($this->id, $p1->x, $p1->y, $p2->x, $p2->y, $color);
  }
}

というような形で上手く収まるんですが、PHPのような動的言語はオーバーロードができないので引数の数や型を自力で調べて適切に例外を出したり…というとても面倒な事になります。

引数の数をチェックするだけにしても

class Image
{
  protected $id; // 画像リソースID

// コンストラクタ等省略...

  public function drawLine()
  {
    // 引数の数をチェックし、
    // 数が5ならdrawLine(int $x1, int $y1, int $x2, int $y2, int $color)、
    // 数が3ならdrawLine(Point $p1, Point $p2, int $color)とみなします。
    $args = func_get_args();
    switch (count($args)) {
    case 5:
      list($x1, $y1, $x2, $y2, $color) = $args;
      break;
    case 3:
      list($p1, $p2, $color) = $args;
      list($x1, $y1, $x2, $y2) = array($p1->x, $p1->y, $p2->x, $p2->y);
      break;
    default:
      // argument exception...
    }

    return imageline($this->id, $x1, $y1, $x2, $y2, $color);
  }
}

のようにどうにもすっきりしません。これが例えば

  1. 線を引くメソッドはdrawLine(int $x1, int $y1, int $x2, int $y2)としたい
  2. drawLine(int $x1, int $y1, int $x2, int $y2, int $color)ともできるようにしたい

だけであれば、PHPにはデフォルト引数があるのでそれを使って

class Image
{
  protected $id; // 画像リソースID

// コンストラクタ等省略...

  public function drawLine($x1, $y1, $x2, $y2, $color=0x000000)
  {
    return imageline($this->id, $x1, $y1, $x2, $y2, $color);
  }
}

とするだけでいいんですが…。こういう場合は静的言語の方が親切ですよね。

追記(6月1日)

もとの話とはそれるんですが、GIFはインデックスカラーなので上のコードのように$colorにRGB値をそのまま入れてもだめで、ちゃんとimagecolorallocate()等で割り当てしたインデックス値を入れないといけませんでした。サボったらだめですね。

2010-05-08

DateTime::add(), DateTime::sub()での月の計算

PHPのstrtotime()やDateTime::modify()で月の計算をすると余った日数が無視されずそのまま加算されてしまうので使い勝手が悪い(例えば 2010-03-31 + 1month == 2010-04-31 == 2010-04-30 + 1 day == 2010-05-01 であり、2010-03-31 - 1month == 2010-02-31 == 2010-02-28 + 3 day == 2010-03-03)んですが、DateTime::add(), DateTime::sub()だともしかしたら余った日数を無視するようになっているんじゃないかと思って試してみたところ…同じ結果でした(がっかり...)。

$date = new DateTime();
$interval = new DateInterval('P1M');
$format = 'Y-m-d';

echo 'PHP: ' . PHP_VERSION . PHP_EOL;
echo 'date: ' . $date->setDate(2010, 3, 31)->format($format) . PHP_EOL;
echo ' +1m: ' . $date->setDate(2010, 3, 31)->add($interval)->format($format) . PHP_EOL;
echo ' -1m: ' . $date->setDate(2010, 3, 31)->sub($interval)->format($format);
(結果)
PHP: 5.3.0
date: 2010-03-31
+1m: 2010-05-01
-1m: 2010-03-03

DateIntervalのもとになっているのがISO 8601のdurationなんですが、ISO 8601:2000の和訳のJIS X 0301:2002をざっと見ても時間長(duration)の計算に関する記述がないようなので、そもそも定義されていないのかもしれません。

同じようにISO 8601のdurationがもとになっているXML Schema DatatypesのdurationだとE.2 Commutativity and AssociativityTime durations are added by simply adding each of their fields, respectively, without overflow. (時間長は各フィールドの単純な加算によってそれぞれあふれずに加えられる?)となっていて余った日数を切り捨てるようになっているみたいなんですが…。

とりあえず自力で余った日数を切り捨てるしかなさそうです。