ラベル Test の投稿を表示しています。 すべての投稿を表示
ラベル Test の投稿を表示しています。 すべての投稿を表示

2012年2月29日水曜日

PHP でプライベート変数やメソッドをクラスの外から操作する

何のために操作するのか
※本エントリはPHP 5.3.2以上で正常に動きます。

何のためかというと、例えばテストのときに使います。

プログラムの構造を変更するコトを、リフレクションといいます。
リフレクションとは、

プログラムの実行過程でプログラム自身の構造を読み取ったり書き換えたりする技術のことである。
リフレクション (情報工学) | Wikipediaより。

PHPのリフレクションまわりのManualはコチラです。

このエントリの目次
1.このエントリで使うサンプルクラス
2.プライベート変数をクラスの外から操作する
3.プライベートメソッドをクラスの外から操作する
4.最後に

1.このエントリで使うサンプルクラス
<php

class HideyoshiToyotomi {
    //建前
    //(書いてるだけで本エントリでは特に触れません)
    public $statedReason = '信長さまー!';
    //本音
    private $_realIntention = '信長うぜー!';

    //表向きは信長に心酔して仕えているように見えます
    //(書いてるだけで本エントリでは特に触れません)
    public function serveNobunaga() {
        echo '信長様のためなら命も惜しくありませぬ!';
    }   

    //外からは見えませんが、
    //内には天下取りの夢を秘めています
    private function _getTenka(){
        echo 'よっしゃ俺が天下取ったるで!';
    }   
}
HideyoshiToyotomi.php

秀吉の枷という小説を読んでいるので、秀吉クラスを例にしてみました。
(信長に仕えていた頃は「豊臣」ではないですが…豊臣の方が分かりやすいと思ったので。)

以下、秀吉クラスの概要です。

外から見えるのは、
    public $statedReason = '信長さまー!';
という建前と、
    public function serveNobunaga() {
        echo '信長様のためなら命も惜しくありませぬ!';
    } 
という信長への尽力です。

でも外から見えないところには
    private $_realIntention = '信長うぜー!';
という本音と
    private function _getTenka(){
        echo 'よっしゃ俺が天下取ったるで!';
    }
という天下取りの行動が隠されています!

こんなサンプルでよいのか。

2.プライベート変数をクラスの外から操作する
<どうでもいい>
本能寺の変が起こり、秀吉は弔い合戦として光秀を討つことを決めます。
秀吉の本音はいかに…?
</どうでもいい>

private変数である $_realIntention にアクセスできるようにして、秀吉の本音を暴いてみます。

サンプルコードです。
<?php
include './HideyoshiToyotomi.php';

$hideyoshiToyotomi = new HideyoshiToyotomi();
$reflectionClass = new ReflectionClass($hideyoshiToyotomi);

//変数名を文字列で指定します
$realIntention = $reflectionClass
    ->getProperty('_realIntention');
//private変数にアクセスできるようにします。
$realIntention->setAccessible(true);

//getValueメソッドで
//$_realIntention の値を外から取得します
echo $realIntention
    ->getValue($hideyoshiToyotomi) . "\n";

15行目の echo で、$_realIntention = 秀吉の本音 の「信長うぜー!」が外から見えました。

<どうでもいい>
さて、ここで秀吉は黒田官兵衛の言葉で、考えが変わります。
</どうでもいい>

では次に、private変数である $_realIntention = 秀吉の本音について、外から値をセットして変えてみます。

以下がそのコードです。
上記サンプルコードの最後に追加します。
//setValueメソッドで外から値をセットする
$realIntention->setValue(
    $hideyoshiToyotomi,
    '俺が天下人じゃー!'
);
echo $realIntention
    ->getValue($hideyoshiToyotomi) . "\n";

private変数である$_realIntention の値を外から変更し、「俺が天下人じゃー!」という本音になりました!

3.プライベートメソッドをクラスの外から操作する
<どうでもいい>
秀吉は光秀を討つこときっかけに、天下取りの行動をとり始めます。
</どうでもいい>

privateメソッドである_getTenka を外から見えるようにしてみます。

以下がサンプルコードです。
<?php
include './HideyoshiToyotomi.php';

$hideyoshiToyotomi = new HideyoshiToyotomi();

$reflectionClass = new ReflectionClass($hideyoshiToyotomi);

//メソッド名を文字列で指定します
$getTenka = $reflectionClass
    ->getMethod('_getTenka');
//privateメソッドにアクセスできるようにします。
$getTenka->setAccessible(true);
//invokeメソッドにて、_getTenkaメソッドを実行します
$getTenka->invoke($hideyoshiToyotomi);

privateで隠蔽されていた_getTenka メソッドが実行され「よっしゃ俺が天下取ったるで!」と表示されました。

4.最後に
テストで重宝するので書きました。
他にもPHPUnit の モックオブジェクトという便利なものがあるのですが、それはまたの機会に…。

無駄な情報が多くて例が分かりにくかったかもしれません。
ドラゴンボールとかの方がまだ分かりやすかったかしら、と思ってます。

でもCarクラスなどの味気ないサンプルもあれかなあ…と思ったので、秀吉クラスを例としました。

以上です。

2012年2月27日月曜日

Firefox の Selenium IDE で XML(HTML)のテストを少しだけ簡単にするユーザー拡張スクリプトを書いてみた

Seleniumとは

Webアプリケーション用のテストツール。
テストケースはhtmlで記述され、<table>タグ内の<tr>タグ1つが、テストの1手順を示すので見た目にも分かりやすい。

と、本ブログのSeleniumの導入に関するリンク集01という記事に書いています。

FirefoxにはSelenium IDEというとても便利なアドオンがあるので、本エントリはそれを使う前提で書きます。

このエントリの目次
1.テストを書くのが面倒くさいと思いました
2.作成したユーザー拡張スクリプト
3.使い方
4.最後に

テストを書くのが面倒くさいと思いました
XMLやHTMLの検証などで、getElementByIdとかgetElementsByTagName を書くとき、コードが長くなるのが面倒くさかったのです。
なので簡単なユーザー拡張スクリプトを書いてテストコードを書く量を減らします。

ちなみに、Selenium のユーザー拡張スクリプト集の中に、XMLの値を検証するスクリプトがあるのですが、どうやら要素と要素名を一緒くたにして検証する仕様のようで、しっくりきませんでした。

作成したユーザー拡張スクリプト
GitHubにあげました。

4つの関数を作成しました。

__getElementsByTagName : getElementsByTagName のラッパ関数(テストコードの文字数を減らす用)
__getElementById : getElementById のラッパ関数(テストコードの文字数を減らす用)
__getXmlValue : XMLやHTMLの要素の値を取得する関数
__getXmlAttribute : XMLやHTMLの要素の属性値を取得する関数

3.使い方
まず、ユーザー拡張スクリプトの使い方から。

先ほどのGitHubのコードをコピペして、user-extensions.jsというファイル名でどこかに保存します。
で、Selenium IDEにて
「オプション」→「設定」→「Selenium Core 拡張スクリプト(user-extensions.js) のパス」
で、ファイルのパスを指定します。
Selenium IDE を再起動したら、指定したユーザー拡張スクリプトが使用できます。

次に、各関数の使い方です。

Selenium IDE での記述で説明します。
※(「コマンド」と「値」は省略します。コマンドは全てgetEvalを使用し、値は何も指定しません。)

__getElementsByTagName
対象 : __getElementsByTagName('要素名')
HTMLCollectionが取得できます。

__getElementById
対象 : __getElementById('要素のid')
HTMLElementが取得できます。

__getXmlValue (名前がいけてないですが、HTMLでも使えます orz)
対象 : __getXmlValue(何らかのHTMLElement)
要素の値が取得できます。

__getXmlAttribute (名前がいけてないですが、HTMLでも使えますorz)
対象 : __getXmlAttribute('属性名', 何らかのHTMLElement)
要素の属性値が取得できます。

以上です。

4.最後に
色々といけてない所があるかもですが、好きに改変して使用して下さい。

Related Posts Plugin for WordPress, Blogger...