PHP修行 「setter/getter」を知るの巻
2010.02.17追記 PHPでは「カプセル化」でググる
2010.02.17追記 オブジェクト、getter/setterについての解説
この前書いたMVC勉強のコメントにて添削をして頂いてる最中なのですが、その中でまたもや新たなキーワードが出てきまして・・・。添削して頂いてる最中ですが、分からないコトが出てきたので、先にそっちの勉強して出直してきます。先生、すみません。しばしお待ちを・・・。そんでもって、分からなかったのがこの一文。
setterで値セット、getterで値取り出し。setter,getterを使うことで複数人で開発時に"誰かが勝手なルールで"$nameの値を変更してしまうことを防げる。
ちょっと待って。「setter」「getter」は初耳。教えて!google先生(n'∀')η
(n ▼ω▼ ) < setter getter とは - Google 検索
PHPのそれについて書かれているサイトがなかなか見当たらないのだけれども、とりあえず言語を問わず、「オブジェクト指向」に関するキーワードのようだ。多分。ここからはいろんなサイトで情報をあさりつつ、足りない頭をフル回転して自分なりに自問自答、解釈した内容。間違ってたらツっこみお願いします><
「setter/getter」は何のために?
- publicなプロパティは隠したい。これがことの始まり。
- 隠したいのはなぜ?→外から直接アクセスするのはよくないから。
- なんで直接アクセスはダメなのか?→クラスのプロパティにクラスの外から直アクセスして値を書き換えるコト自体が基本的によくないの!
- なんで?→そういうものなの!『複数人で開発時に誰かが勝手なルールでプロパティの値を変更してしまうことを防げる。』ってコメントで教えてもらっただろーがー!ああ、なるほど。
- んじゃ直アクセスせずにどうしようか?→だから「setter」「getter」の仕組みを使うんだってば。
- どゆこと?→プロパティに直アクセスするんじゃなくて、setメソッドを用意してプロパティの値をセット、getメソッドを用意してそれを返してあげる。
つまり、プロパティへ直接アクセスじゃなくて一旦メソッドを経由してプロパティをいじろうね、ということらしい。多分。
では、そのやり方は?
マニュアル探しまくったけど「setter」も「getter」もない。「set」も「get」ない。似た感じで怪しいのはあったんだけど→PHP: オーバーロード - Manual なんかコレが近い気がする。しかし「オーバーロードメソッドが起動するのは、 宣言されていないプロパティやメソッドを操作しようとしたときです。
」と書いてある。いや、私はプロパティを宣言している。従ってこれは関係ないと判断。が、「また、現在のスコープからは アクセス不能な プロパティやメソッドを操作しようとしたときにも起動します。
」とも書いてある。わからん。一体何の話だ。これは日本語なのか?難しいよぉ・・・。とりあえず一旦スルー。
で、何?結局どうすればよいの?って一瞬ひるんだけど、私は諦めないっ。
「おう、私はred_hippy、あきらめの悪い女・・・」
これ便利ですよと教えてもらったジェネレータのURLへアクセス!
なんか適当に下のExample Codeの変数の辺りをコピペして「Go」クリック!
何回かやってみたけど意味分からない。「一体何するものコレ?」状態。8回くらい「Go」をクリックしてからやっとピーン!と繋がったwwwww
あぁ、自分でそれを用意するのですね。そのためのこのツールなのですね(恥
気付くの遅くてごめんなさい。愚かな私でごめんなさい。自分の脳内ではそれらは勝手にPHP側で用意してくれてる関数か何かの中に「set」とか「get」とかあってそれを利用するんじゃないかと思い込んでました。全然違ってました。ごめんなさい。自分で用意するのですよ、皆さん。ピーンときたと同時に、このジェネレーターツールが便利というその意味も分かりました。確かにコレ使ったほうが早い。便利だー!
こういうのを自分で用意すればよい、と。
「setter」「getter」を使う理由
- 「setter」「getter」を利用すれば、複数人で作業をする際にも他の人間が勝手に予想外の値を入れたりして「アーーー!」ってなるのを防げる。
- 「setter」「getter」を利用していれば、それらの内容が変わっても呼び出す側には影響しない。
こんなページも発見。
>>» オブジェクト指向プログラムで getter/setterメソッドを使わなければならない 10の理由 Pattern: Pattern Ref —自分用覚書
書いてある事の半分も分からないけれども一番最後の理由が超分かりやすい。
オブジェクト指向とはそういうものである。
うおー。なんか超カッケー。そういうものなのですよ、きっと。
疑問に思ったこと/ググっても分からなかったこと
PHPはsetterで値のチェックはできないの?
PHPに拘らずサイト巡りをしていると、setterで値の型をチェックできるという風な話が出ていたのだけれど(数値を入れる変数に文字は入れない様にできるとか)それはPHPではどう書けばいいのだろう?全然見当違いな話なのでしょうか・・・はて?
↑自前でチェックコードを記述すればいいだけの話だった。なんか特殊な型を調べる書き方とかあるのかと勝手に思い込んでた><
なんでPHPではsetter,getterを使わないの?
もう一度頂いたコメントを読み返してみると『※PHPではsetter,getterがない例も多い。
』と。それはなぜ?まぁPHPだからとか言語に拘って考えるのが違ってるのかもしれない。オブジェクト指向だからこういうsetter,getterという考え方をするも良いという話なのかもしれない。そういうことにする。
↑コメントにて「PHPはスクリプト言語なのでgetter,setterを使うとコードが冗長になって速度面などで不利になるからかなぁなんて思ったり。あとはcakePHPなどのフレームワークを使うとgetter,setterなんかは見えないのでみんな気にしてないんじゃないかな^^;
」という意見を頂いた。
PHP5では、__set/__get がある!
追記:すみません。違ってましたw 以下すっげー変なコト書いてます。
ここから下はちょっと間違ってる内容のようです。再びMVCのページのコメントで「未定義のプロパティを取得・設定しようとしたタイミングで呼び出されるメソッドなので、getter,setterとはちょっと違いますね。」と教えていただきました。この部分、全部削除してしまおうかとも思ったんですが、短時間でも一度公開してしまったので、一応そのまま残しておきます。勉強記録的な感じで・・・。が、スルー推奨。
三度追記・・・いや、「間違い」ではなかったみたい。頂いたコメントより抜粋。コメント「__get,__setはgetter,setterとしても使えるので「間違い」ではないです。下のPHP公式マニュアルのオーバーロードの例ではsetter,getterとして使用してます。
」
オーバーロード
開発のスタイルにあったものを選択すると良いらしい。
で、上で書いたPHP: オーバーロード - Manualについて悶々としてると、ナイスタイミングできのこ先生から追加コメントキタ━━━━(°Д°)━━━━!!!!
PHP5からは__set,__getというマジックメソッドがありますね。プロパティをprivateで宣言すれば、このマジックメソッドが自動で実行されるらしい。自分のルールでset,getしたい場合はこれらのメソッドをオーバーロードすればよいです。
先生、ホントにいいタイミングのコメントです。ネ申サンクス。どこかから私の今の様子を覗いているのではないかというくらいのタイミングでした。
ということで、私はPHP5を修行中なので、こちらの「__set」「__get」を利用するとよいのですね。
つーことで、ちと実験タイム
こんな感じで試してみました。
こうすることで、呼び出す側ではプロパティを直接呼び出してるような感じで実はメソッドを経由して呼び出してるっていう仕組みになるんですね。へぇーー。いやでも「ホントに分かった?」と聞かれるとsetter,getterを使う理由や意味は分かったけど、なんか変なことになってるんです。上に書いたソースがどこか間違っているのかもしれないんですが、何か適当に例えばこういうのを追加すると「$test->sample2 = "これはテスト2です。";echo $test->sample2;」それが普通に出てくるんです。頭が半分寝てて何かおかしなことをいってるのかもしれない。あれれ。クラスの中で定義してない変数ってこういう風にしたら出てくるんだっけ・・・。根本的にクラスの所から間違ってるかも・・・。ダメだ。寝てます。もう頭回ってない><
明日もうちと練習します><
関係ない話ですが、こういうの教えてもらう時に「○○するとよいです。」って言い切りの形で言ってもらえるとすごくありがたいですね。勇気100倍。100%勇気。眠たくなってきて変なテンションでごめんなさい。
2010.02.17追記 PHPでは「カプセル化」でググる
一夜明けて朝からTwitterで@kamiyamさんと@redsnow_さんからアドバイスを頂いた。んでもって「PHPだとこのあたり調べるといいかも」と新たなキーワード「カプセル化」という言葉を知った。聞いた事はあったけど、ちゃんと意味わかってなかった。
これはまさに昨日の夜戦ったsetter,getterの考え方なのでは!
>>php フレームワーク・オブジェクト指向入門: カプセル化
>>「カプセル化」のアーカイブ | オブジェクト指向PHP
上の方のページのサンプルソースではこの考え方を利用するメリットがよく分かった。確かにそうしておくと仕様変更になった場合でも楽ですねー。
そしてもう一つ、お約束事みたいなのも書いてあった。「読み込み用のメソッド名は、getプロパティ名、書き込み用のメソッド名は、setプロパティ名
」とするとよいのですね。(多分別にそうでなくてもいいのだけと思うけど、頭にgetやsetを付けると分かりやすいし一般的によく使われてるよという意味なのではないかと思う)
そして「こういった単純なゲット、セットだけをするメソッドをアクセサメソッドといいます。
」と。getterメソッドとsetterメソッドの総称みたいなものをアクセサメソッドというってことでいいのかな。getterとかsetterの事をまとめてアクセサメソッドって言うよ、みたいな。
オブジェクト、getter/setterについての解説
@ukstudioさんさんがオブジェクト、getter/setterについての解説エントリを書いてくださいました。
全然適当じゃない。むしろ理解度がかなりレベルアップした気がします。お忙しい中、わざわざありがとうございました!感謝します!
>例えばあるデータには数値だけ、文字列だけ入れたいというチェックもsetterでやることができる。
上の方で疑問に思ったことの部分に書いたけど、やっぱりそういうことできるんだ。やり方が分からない。後でもっとググってみます。自前でチェックコードを記述すればいいだけの話だった。なんか特殊な型を調べる書き方とかあるのかと勝手に思い込んでた><
メンバ変数をこういう風にまとめたらいいよの例の部分、すごく納得でした。奥深そうでまだ完璧に分かってないけど、なんせ修正する際の手間減るような考え方も必要ってことですよね。なるべくシンプルな書き方をして再利用しやすくしておくってのも大事なのかなと思いました。
もっともっと知りたくなりました。ホントにありがとうございました!
<< 素敵★ノンプログラマのためのPHP入門 | PHP修行 MVC復習/改善の巻 >>
トラックバック
このエントリーのトラックバックURL:
http://redline.hippy.jp/cgi/mt/mt-tb.cgi/256
コメント (12)
最近flashとphpとの連携やら、flashとjavascriptなんて案件がありまして…。
Redさんのphpのソースを見るとActionScript3.0の概念と同じだな~って思います。getter,setter,クラスなどなどなど。
いや~、言語は違うけど勉強になります。
投稿者: painkiller | 2010年02月17日 10:13
>painkillerさん、こんにちわー。
私もいろいろ調べているうちに気が付いたらASのページに辿りついたりして、似てる感じなのかなーとか思ってたところでしたw
オブジェクト指向っていう考え方自体は言語問わず概念は同じで、一度そういう概念みたいなものをキチンと理解できたら言語が違っても通じるものがあるってことなんですかねー。ホントに外国語を勉強してるのと同じ感じなんですね。
投稿者: Red | 2010年02月17日 11:58
__get,__setはgetter,setterとしても使えるので「間違い」ではないです^^;以下のPHP公式マニュアルのオーバーロードの例ではsetter,getterとして使用してます。
http://php.net/manual/ja/language.oop5.overloading.php
__get,__setをgetter,setterとして使用するのは「間違い」ではなく、私の中ではなんか違う!きもい!と思っただけですw速度面でもデメリットがあるようですし。
http://ameblo.jp/koexuka/entry-10116783597.html
ここに書いてあるように「開発のスタイルにあったものを選択すると良い」のではないでしょうか。
http://d.hatena.ne.jp/tune34/20080129/1201534331
>PHPはsetterで値のチェックはできないの?
自前でチェックコードを記述すればよいのでは?
>なんでPHPではsetter,getterを使わないの?
私が見たソースが使っていなかっただけで、他はちゃんと使ってるのかもw
PHPはスクリプト言語なのでgetter,setterを使うとコードが冗長になって速度面などで不利になるからかなぁなんて思ったり。でも私はgetter,setterはちゃんと用意する派です。
あとはcakePHPなどのフレームワークを使うとgetter,setterなんかは見えないのでみんな気にしてないんじゃないかな^^;
おまけ:
PHPのオブジェクト指向については以下が簡潔にまとまっていたのでご参考にどうぞ。
http://www.cc9.ne.jp/~initialize/text/php/php_02.html
投稿者: きのこる | 2010年02月17日 13:22
>きのこる先生
たくさんいろんな勘違いをしてしまった><
setter,getterを使う意味自体は理解できた気がします。素朴な疑問にもお答え頂いてありがとうございました。勘違いしまくっててもう恥ずかしくて死にかけです><
でも、とりあえず、いっぱい新しい考え方とか言葉を覚えられて楽しいですw
投稿者: Red | 2010年02月18日 08:57
マジックメソッド(__get()/__set())について実験されているところに関して、少し長くなりますが説明させていただきます。
PHPのオブジェクトは非常にゆるいのです。
クラス内に定義していないプロパティ(実験されているところのsample2)を外部からセットすると、オブジェクトにpublicなプロパティとして定義されてしまいます。
sample2をセットしたときには"__set()しましたー!"という文字列は出力されていると思いますが、そのとき同時にpublicなプロパティとしてsample2が定義されることになります。
その後、sample2を取得しようとすると、これはpublicなプロパティとして存在してしまっているので__get()を介さずに取得できると言うことになります。
ちなみに、プロパティがクラスに定義されているかを判定するproperty_exists()関数がPHPにはあります。
http://jp.php.net/property_exists
また、Javaなどのように、メソッドや関数の引数の型をチェックする「タイプヒンティング」という機能もPHP5にはあります。
http://php.net/manual/ja/language.oop5.typehinting.php
public function setUser(User $user)
のようにすると、Userオブジェクトと見なされないものが渡された場合、エラーになるというものです。
これは厳密にチェックしたい場合などに使われますが、オブジェクトの型か配列にしか対応していません(文字列か数値か、といった判定はできません)。
もし引数の型のチェックが必要というのであれば、(拡張などが面倒くさくなるというデメリットはありますが)こういった機能も活用してみるといいかと思います。
投稿者: fivestar | 2010年02月19日 22:44
>fivestarさん、教えていただいてありがとうございます!
>そのとき同時にpublicなプロパティとしてsample2が定義されることになります。
なるほど。その辺り、全然分かってませんでした。var_dumpで調べた時もクラス内で定義してるsampleの方は「sample:private」となってたんですが、後から追加したsample2の方は単に"sample2"となってるだけで、これはどういうことだろうと思ってたんですが、publicなプロパティが新しくセットされたってことだったんですね。今までアクセス修飾子部分、何も気にしてなくてvar_dumpで調べても「:private」とか出てこなかったのは全部publicプロパティだったからだったんだと気付いて恥ずかしくなりました。あーもう、分かってなかった><
>property_exists()関数
試してみました。クラス内にファンクションを入れてみたら、sampleの方はtrueになってsample2はfalseになりました。これはクラスの中からsampleにアクセスできるからTrue、sample2はそうでないからfalseになる。クラスの外で調べたら両方falseになったけど、それはsampleプロパティが外からアクセスできないprivateだからfalseになってる・・・ってことですよね。
>タイプヒンティング
これも初耳でした。とりあえずマニュアルの例文でテストして何が動作して何が動作しないのかは確認して「あぁ、こういうものなのだな」とは分かったんですが、使い方が難しい・・・。まだちゃんと理解できてなさげです。
単純に数値かどうかを調べるにはctype_digit関数やis_numeric関数、文字列かどうかを調べるにはis_string関数とかを使えばいいのでしょうか。。。
投稿者: Red | 2010年02月21日 12:53
バリデーション(入力値チェック)は、いろいろ方法があります。
・地道にpreg_match()などでチェックする。
例)http://d.hatena.ne.jp/Arko/20090318/1237363684
・自前でValidatorクラスを作成
・既存のValidatorクラスを使用
例)http://www.majima.net/php/Validation/index.html
バリデーションはフレームワークを使うとかなり簡単になります。例えばcakePHPなどでは以下の定義をモデルにするだけでバリデーションを行ってくれます。
var $validate = array(
'login' => 'alphaNumeric',
'email' => 'email',
'born' => 'date'
);
フレームワークもよいのですが、私的には1度だけでも素のPHPでプログラムを組んでみることは必要だと考えています。本質を知らないと応用がきかないと考えていますので^^;
以下に素のPHPのMVCサンプルが!簡単なサンプルなので理解しやすいかも。
http://www.objective-php.net/mvc/
あ、上記サンプルはバリデーションはしてないので注意orz
投稿者: きのこ | 2010年02月22日 20:29
はずかしいだなんてとんでもない、PHPが変なだけですよw
ここまでわかってるのですから十分すごいと思います。
プロパティに関してはおっしゃるとおりです。ただ、property_exists()関数はPHP 5.3.0から挙動が変わって、アクセス修飾子にかかわらずプロパティが定義されていればtrueを返すようになります。
タイプヒンティングは、より厳密にプログラムを書くためのものなので、急いで覚える必要はないです。
プログラムが大きくなると、オブジェクトの数も増え、継承構造も複雑になってきたりします。
そこでタイプヒンティングを指定しておくとミスの防止にもなり、また引数として何のオブジェクトを期待するのかがわかりやすくなるといったメリットがあります。
数値などのチェックは挙げている関数で基本的にはいいと思います!
PHPに関してわからないことがあったら、twitterとかで聞いていただければ大抵のことはお答えできると思いますので、お気軽に聞いてくださいねー。
http://twitter.com/fivestr
投稿者: fivestar | 2010年02月23日 02:56
>きのこ先生
またまたたくさん新しい事を教えてくれてありがとうございます。
そうかそうか。綿密に内容をチェックしたい場合は正規表現を使えばいいんですね。
随分前に正規表現の基本的な事を勉強してみたんですが、これってね、基本的なそれぞれの記号や英数字が何を意味するものかがわかったら、本職のプログラマさんはどっかのサイトで公開されている該当部分をコピーペーストして使ってるものなんですか?それとも毎回1から自分で考えて書く、もしくは自分で1回書いてそれを使いまわしとかするのでしょうか・・・。とか、ちょっとそんな素朴な疑問が沸きましたw
>Validatorクラス
なんか便利そう!ちゃんと一度使ってみないと分かった気で終わりそうなので後でちゃんと試してみますー。
MVCの参考サイトもお教え頂いてありがとうございました。量が少なめのそういったソース見るとわかりやすいですねw (量が多いと圧倒されてしまって><)
後でちゃんと全部見てみます!
投稿者: Red | 2010年02月23日 09:58
>fivestarさん、ありがとうございますー。
>ただ、property_exists()関数はPHP 5.3.0から挙動が変わって
なるほど。バージョンによっての動作の違いも覚えておいた方がいいんですね。マニュアル見てみたらちゃんと変更履歴の部分に書いてありましたね・・・普段その辺りは注意して見てなかったので他の関数等でも調べたときは確認するようにしますー。
>タイプヒンティングは、より厳密にプログラムを書くためのものなので、急いで覚える必要はないです。
あ。ちょっとホっとしましたw
でもそういうの分かってるのと分かってないのは違うんだろうなーという雰囲気はヒシヒシと感じるのでおいおい身につけたいです。
Twitterでも見つけてくださってありがとうございました。また私が変な事書いてたらツっこみお願いします(n' ω 'n)
投稿者: Red | 2010年02月23日 10:05
Zendのvalidatorも便利そう。
http://blog.justoneplanet.info/2009/09/28/zendframework-zend_validate%EF%BC%88%E3%83%90%E3%83%AA%E3%83%87%E3%83%BC%E3%83%88%EF%BC%89/
>もしくは自分で1回書いてそれを使いまわしとかするのでしょうか・・・。
私の場合以下のような感じかなぁ。
1.ネットで探す
2.必要があれば改造
3.使い回し
自分で1から作ったモノなどないですw
正規表現は、よいサンプルがたくさん転がってますのでそれを使うとよいですよ。たまに間違っているものもありますが^^;
投稿者: きのこ | 2010年03月01日 13:42
>きのこさん
ふむふむ。そういうモノなんですね。
>自分で1から作ったモノなどないですw
安心しましたww
投稿者: Red | 2010年03月03日 12:55