prefabolic

123456789101112131415161718192021222324252627282930
HOME > Category : Programming   ↔ See also Archive
«Prev | 1 | 2 | 3 | Next»

phpにもC#のプロパティ, rubyのattr系のアレが欲しい

最近phpをあまり追ってないのでよくわからないんだけども
getter,setterのようなaccessorメソッドはphp5でも地道に書くしかないんだよね?

__get(), __set()は知っているのだけれども
ちょっと違うんだよなあ。
いや出来たとしても記述が冗長になり過ぎる。

やりたいことは
1. フィールドに直接アクセスしているように見える
2. でもメソッドを介しているので呼び出し側が意識しなくても呼び出される側で色々チェックが出来る
3. 明示的にフィールド名を宣言できる。というか宣言していないフィールド名を設定、参照することができなくしたい
4. getHoge(), setHoge()などとだらだら書きたくない

多分できなくはない、でもスマートに書ける気がしない。
簡単に書けるように基底クラスにめんどくさい実装をしてしまえと思って少し書いてみた。

#!/usr/local/bin/php
<?php
class AttrClass
{
    private $attr_reader = array();
    private $attr_writer = array();
    private $attr        = array();

    protected function attr_accessor($attributes)
    {
        $add = $this->_my_flip($attributes);
        $this->attr_reader = array_merge($this->attr_reader, $add);
        $this->attr_writer = array_merge($this->attr_writer, $add);
    }

    protected function attr_reader($attributes)
    {
        $add = $this->_my_flip($attributes);
        $this->attr_reader = array_merge($this->attr_reader, $add);
    }

    protected function attr_writer($attributes)
    {
        $add = $this->_my_flip($attributes);
        $this->attr_writer = array_merge($this->attr_writer, $add);
    }

    private function _my_flip($mixed)
    {
        if (! is_array($mixed)) {
            $mixed = array($mixed);
        }
        return array_flip($mixed);
    }

    private function __set($name, $value)
    {
        if (array_key_exists($name, $this->attr_writer)) {
            $this->attr[$name] = $value;
        } else {
            throw new Exception("$name is undefined setter method");
        }
    }

    private function __get($name)
    {
        if (array_key_exists($name, $this->attr_reader)) {
            return $this->attr[$name];
        } else {
            throw new Exception("$name is undefined getter method");
        }
    }
}

class Klass extends AttrClass
{
    function __construct($foo, $bar, $baz)
    {
        $this->attr_accessor(array('foo', 'bar', 'baz'));
        $this->foo = $foo;
        $this->bar = $bar;
        $this->baz = $baz;
    }
}

$kls = new Klass('FOO', 'BAR', 'BAZ');
echo $kls->foo . PHP_EOL;
echo $kls->bar . PHP_EOL;
echo $kls->baz . PHP_EOL;

$kls->bar = 'バー';
$kls->baz = 'バズ';
echo $kls->foo . PHP_EOL;
echo $kls->bar . PHP_EOL;
echo $kls->baz . PHP_EOL;

$kls->hoge = 'HOGE';
?>
メソッド名はrubyのぱくり。
これを実行すると
FOO
BAR
BAZ
FOO
バー
バズ

Fatal error: Uncaught exception 'Exception' with message 'hoge is undefined setter method' 
...
ここまではOK。

次はなんらかのドメインロジックを持ったアクセサを定義する場合、
子クラスにdummyのアクセサを実装して
親クラスにattr_[writer|reader]_user_funcなどと言うアクセサを登録するメソッドを実装して
親から子のアクセサをcall_user_funcしてみる。

まずは親クラスの実装(変更箇所のみ)
    protected function attr_reader_user_func($attribute, $class, $func)
    {
        $this->attr_reader[$attribute] = array($class, $func);
    }

    protected function attr_writer_user_func($attribute, $class, $func)
    {
        $this->attr_writer[$attribute] = array($class, $func);
    }
...
    private function __set($name, $value)
    {
        if (array_key_exists($name, $this->attr_writer)) {
            if (is_callable($this->attr_writer[$name])) {
                call_user_func($this->attr_writer[$name], $value);
            } else {
                $this->attr[$name] = $value;
            }
        } else {
            throw new Exception("$name is undefined setter method");
        }
    }

    private function __get($name)
    {
        if (array_key_exists($name, $this->attr_reader)) {
            if (is_callable($this->attr_reader[$name])) {
                return call_user_func($this->attr_reader[$name]);
            } else {
                return $this->attr[$name];
            }
        } else {
            throw new Exception("$name is undefined getter method");
        }
    }

次に子クラスとメイン部分の実装
今回はfooの値を必ず小文字にしてびっくりマークを付けるように実装してみる
class Klass extends AttrClass
{
    function __construct($foo, $bar, $baz)
    {
        $this->attr_accessor(array('foo', 'bar', 'baz'));
        $this->attr_writer_user_func('foo', $this, 'set_foo');

        $this->foo = $foo;
        $this->bar = $bar;
        $this->baz = $baz;
    }

    protected function set_foo($value)
    {
        $this->foo = strtolower($value) . '!!';
    }
}

$kls = new Klass('FOO', 'BAR', 'BAZ');
echo $kls->foo . PHP_EOL;
echo $kls->bar . PHP_EOL;
echo $kls->baz . PHP_EOL;

$kls->bar = 'バー';
$kls->baz = 'バズ';
echo $kls->foo . PHP_EOL;
echo $kls->bar . PHP_EOL;
echo $kls->baz . PHP_EOL;

$kls->hoge = 'HOGE';

これで実行すると
foo!!
BAR
BAZ
foo!!
バー
バズ

Fatal error: Uncaught exception 'Exception' with message 'hoge is undefined setter method'
...
成功!!!

のように思えるけど、実はこれダメダメで、
例えば以下のように2回fooをセットしてみると
$kls = new Klass('FOO', 'BAR', 'BAZ');
echo $kls->foo . PHP_EOL;
echo $kls->bar . PHP_EOL;
echo $kls->baz . PHP_EOL;

$kls->bar = 'バー';
$kls->baz = 'バズ';
echo $kls->foo . PHP_EOL;
echo $kls->bar . PHP_EOL;
echo $kls->baz . PHP_EOL;

$kls->foo = 'FOO2';        ←ここを追加
echo $kls->foo . PHP_EOL;  ←ここを追加

$kls->hoge = 'HOGE';
追加した部分に関しては
foo2!!
と表示されて欲しいのだけれども、
foo!!
BAR
BAZ
foo!!
バー
バズ
FOO2 ←あーあ・・・

Fatal error: Uncaught exception 'Exception' with message 'hoge is undefined setter method'
...
となってしまった。

今日はここで力尽きる。。
投稿者:kalibora
投稿日時:2007-06-24 - 01:33:39
カテゴリー:Programming - Permalink - - トラックバック(DISALLOWED (TrackBack)) -

ふぃずばず

どうしてプログラマに・・・プログラムが書けないのか?

1から100までの数をプリントするプログラムを書け。ただし3の倍数のときは数の代わりに「Fizz」と、5の倍数のときは「Buzz」とプリントし、3と5両方の倍数の場合には「FizzBuzz」とプリントすること。


rubyの勉強中なのでrubyで書いてみた。
$ ruby -e "(1..100).map {|i| case true when i%3==0 && i%5==0 then 'FizzBuzz' when i%3==0 then 'Fizz' when i%5==0 then 'Buzz' else i end}.each {|v| print v, ' '}; puts"
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 31 32 Fizz 34 Buzz Fizz 37 38 Fizz Buzz 41 Fizz 43 44 FizzBuzz 46 47 Fizz 49 Buzz Fizz 52 53 Fizz Buzz 56 Fizz 58 59 FizzBuzz 61 62 Fizz 64 Buzz Fizz 67 68 Fizz Buzz 71 Fizz 73 74 FizzBuzz 76 77 Fizz 79 Buzz Fizz 82 83 Fizz Buzz 86 Fizz 88 89 FizzBuzz 91 92 Fizz 94 Buzz Fizz 97 98 Fizz Buzz

答えが合っているのか。
アルゴリズムはどうなのか。
そしてruby的にどうなのか。
投稿者:kalibora
投稿日時:2007-05-10 - 01:44:42
カテゴリー:Programming - Permalink - - トラックバック(DISALLOWED (TrackBack)) -

zsh+compinit+make

今makeファイルの勉強を家でしていたらちょっと驚きの事実発見。
zshはmakeのターゲットまで自動で補完するのね・・。
もちろんそのときのMakefileの中身から引っ張ってきてる。
すげー便利。

なんだけどこんなに便利だと会社で使えないのが痛くなってくるなぁ。
投稿者:kalibora
投稿日時:2007-04-07 - 15:25:22
カテゴリー:Programming - Permalink - - トラックバック(DISALLOWED (TrackBack)) -

続・ジョエル・テスト

ジョエルテストっていうのは
1個前のエントリで書いた
joel on softwareの著者であるjoel spolskyが考えた
ソフトウェア開発チームのよさを調べるための誰でも簡単に出来るテストのこと。
詳しくはここを読んで欲しい。
で、内容は以下の項目についてYes/Noで答えるだけ。10ポイント以下ならやばいんじゃない?ってことらしい。
  1. バージョン管理システムを使っているか?
  2. 1オペレーションでビルドを行えるか?
  3. 毎日ビルドを行っているか?
  4. バグトラッキングシステムを持っているか?
  5. 新しいコードを書くまえにバグを修正しているか?
  6. 更新可能なスケジュール表を持っているか?
  7. 仕様書を持っているか?
  8. プログラマは静かな労働環境にあるか?
  9. 買える範囲で一番良い開発ツールを使っているか?
  10. テスト担当者はいるか?
  11. プログラマを採用するときにコードを書かせるか?
  12. 「廊下でユーザビリティテスト」を行っているか?

前の会社にいたときもやったんだよね。
リンク先を見てもらえばわかるんだけどそのときは3点だった。

じゃあ今のチームはどうだろう。

  • バージョン管理システムを使っているか?
バージョン管理システムは使ってるには使ってるけどリリース時のバックアップ目的にしか使ってないので0.5点。
開発時には使ってないのでデグレの危険性や手動マージのめんどくささが問題点。

  • 1オペレーションでビルドを行えるか?
これは今webアプリだからビルドとは違う概念で、1オペレーションでデプロイできるか?と等価だとすると出来ない。運用、リリースコストはかなりかさんでる状態。
なので0点。

  • 毎日ビルドを行っているか?
これもwebアプリだからなぁ。。
毎日単体テストしてるか?と等価とすると、、
そもそも単体テストスクリプトを書こうとする人があまりいない。0点。

  • バグトラッキングシステムを持っているか?
使ってない。
まぁでも必要に応じてエクセルで管理してるから0.5点にしておくか。

  • 新しいコードを書くまえにバグを修正しているか?
これはしてるかな。1点。

  • 更新可能なスケジュール表を持っているか?
基本的にケツが決まってます。0点。

  • 仕様書を持っているか?
これはそこそこ書いてる。1点。

  • プログラマは静かな労働環境にあるか?
メッセンジャーがうるさい場合もあるけど、ヘッドフォンで音楽聴けるし0.5点。

  • 買える範囲で一番良い開発ツールを使っているか?
ふぁっク!
Notデュアルディスプレイ。環境は個人個人に割り当てられていない。0点。

  • テスト担当者はいるか?
これいるっていうのかな。ある意味いる。
でもうーん。中途半端なんだよな。立場が。
0.5点。

  • プログラマを採用するときにコードを書かせるか?
なにも。
適当に取っているとしか思えない。0点。

  • 「廊下でユーザビリティテスト」を行っているか?
ない。0点。

以上!
つーことで足すと、
合計4点です!!

よっしゃ前チームより1点あがってる!
投稿者:kalibora
投稿日時:2007-03-18 - 02:53:27
カテゴリー:Programming - Permalink - - トラックバック(DISALLOWED (TrackBack)) -

ハッカーと画家とjoel on software

似た種類の内容だけど、対照的でもある2冊。

ハッカーと画家はへこんでるときに読むとこれでいいんだって勇気付けられる良本。
joel on softwareは現実的な落とし所が書かれている良本。
読んでいて純粋に楽しいのはハッカーと画家の方。
だって夢が書かれているから。
joel on softwareはくっそーと思うんだよね。
説教されてるみたいな。
でもそれも必要なんだろうな。

ハッカーと画家はプログラミングが好きな人だけ読めばいいと思うし、お勧めはしない。ってかする必要が無い。好きな人は勝手に読んでいると思うので。

joel on softwareは職業プログラマは読んで損しない本だと思う。
すべて鵜呑みにする必要は(すべての本に言えることだけど)ないと思うんだけどよい指針になるはず。

今日読んだ部分でなるほど、と思ったところ。
漏れのある抽象化の法則にあった一節。


抽象化は私たちが作業する時間を節約してはくれるが、私たちが学ぶ時間までは節約してくれないのだ。



いくら抽象化しても結局下のレイヤを学ばなければどこかでつまずくのは避けられない。
それは最近つくづく感じているところで、
かといって抽象化=悪(こう思ってる人もけっこういるんだ)というわけでもなく
一度学んでしまえばよいわけでそれからは便利に使っていけばよいと。

ここらへんはまたあとで考えよう。
投稿者:kalibora
投稿日時:2007-03-18 - 02:06:29
カテゴリー:Programming - Permalink - - トラックバック(DISALLOWED (TrackBack)) -

クロージャ

クロージャで遊んでみた
しかしいまいち概念と使いどころが理解できない。。
そういや昔はオブジェクト指向もそんな感じだったな。
投稿者:kalibora
投稿日時:2007-03-08 - 01:52:20
カテゴリー:Programming - Permalink - - トラックバック(DISALLOWED (TrackBack)) -

lisp

lispむずかしいなぁ。
入門Common Lisp―関数型4つの特徴とλ(ラムダ)計算 を読み終わったけど、最後の方飛ばしちゃった。。
あとでそこらへんは読み返すとして、
今は
On Lispを読み中。
本も出るみたいなので出たらそっちで読みたい。

まださわりだけしか読んでないんだけど

ボトムアップデザインはプログラムを読み易くする.この種の抽象化のインスタンスは,読む人に汎用オペレータを理解するよう要求する.
機能的抽象化のインスタンスは,読む人に特殊目的のサブルーチンを理解するよう要求する
「でもあんたのユーティリティを全部理解しないことには,プログラムが読めなくなるじゃないか.」
そういった言葉は大抵誤りだ.なぜかについては,第4.8節を参照

この4.8節が激しく気になる・・。
ボトムアップデザインがトップダウンより有効かどうかは未だよくわからないんだけど、
プログラマとしてはトップダウンより絶対にやり易いし楽しいな。
投稿者:kalibora
投稿日時:2007-02-20 - 00:44:04
カテゴリー:Programming - Permalink - - トラックバック(DISALLOWED (TrackBack)) -

つれづれ

最近仕事をしてて思うこと、
業務フローを書くならやっぱりスクリプト言語使いたい。
PL/SQL書くの辛い。よくわからんし。。
アプリケーションサーバもC++じゃなくてphpとかにすればコードも半分以下になってかなりDRYに書けるんだけどな。
パフォーマンスは実測してみないとなんともだけど。
投稿者:kalibora
投稿日時:2007-02-18 - 02:34:48
カテゴリー:Programming - Permalink - - トラックバック(DISALLOWED (TrackBack)) -
«Prev | 1 | 2 | 3 | Next»