■
今春からようやく会社でレガシーコード改善ガイドを使って勉強会をするようになった(やっと…!)のでちょっと古いエントリを再掲しておく。
「テストを書けばよいのでは?」の一言がためらわれる時もある
整然とし、秩序だった美しい世界を構築する人がいた。設計もコードも、リファクタリングする指針でさえも一貫したポリシーを持って行われていることが、経験のない僕にもよくわかった。たしかに彼が手を入れた部分は美しかった。でもその周りには広大な廃墟とスラムが存在していたのだ。古い、改修しながら使っているライブラリはすでに原型をとどめていない。彼はすこしずつ手直しをしてすこしずつ改善していたけれども、ライブラリには手をつける暇もなく去っていった。広大なスラムだけが残った*1。
しばらくそこを離れていた僕がもどってきたとき、最初の仕事はコードレビューだった。かの整然とした世界を構築できる人の代わりにしては僕はあまりにも物事を知らなさすぎるが、それでも何百分の一かの貢献は期待されている。
似たようなコードをそのままコピーして新しいメソッドにしている部分を目にして僕は、同じ処理を抽出してメソッド化したらよいのではないかというレビューをしたが、担当者はスラム化したライブラリがうまく動かなくなるのを怖がってその指摘を受け入れなかった。ライブラリにはもちろんテストがない。クラス関係も複雑で、設計書も仕様書もない。そのコードは関連会社から譲り受けたものだから構築した人もいない。そして、設計ができずスキルの低い僕は自信がなかった。それでもやるべきだとは言えなかった。
レガシーコード改善ガイド (Object Oriented SELECTION)
- 作者: マイケル・C・フェザーズ,ウルシステムズ株式会社,平澤章,越智典子,稲葉信之,田村友彦,小堀真義
- 出版社/メーカー: 翔泳社
- 発売日: 2009/07/14
- メディア: 大型本
- 購入: 45人 クリック: 673回
- この商品を含むブログ (152件) を見る
「レガシーコード改善ガイド」を読み始めた。
序文からしてすでに涙目である。
自分のコードがひどいのは前から分かっているし、なにもひどさに涙しているわけではない。
僕はコードが書けない。知識はあっても、簡単なプログラミングができても、僕はコードを書けないと思っている。自信がないのだ。自分が作るものが本当に意図したとおりに動くのか、わからない。作れば作るほど発散し、自分でも構造がつかめなくなっていくことを知っているから怖いのだ。誰かが作ったコードを正確に読み取り、その動作がなんの機能に当たるのか、わかっているつもりになっている気がする。そして僕は変更しない方向を選んでしまう。「できるだけ変更せずにとっておいて新たに書き加える」。その繰り返しが膨大な二度と使わないメソッドとクラスのゴミの山を積み上げることになると知っているのに。
きれいなコードは有益ですが、それだけでは不十分です。テストなしに大規模な変更をしようとすると、チームは危険な賭けに出ることになります。転落防止の網を張らずに空中ブランコをするようなものです。とてつもないスキルが必要であり、ステップごとに何が起きる可能性があるかをきちんと把握しておかなければなりません。
(中略)
ここまで、テストについてかなりたくさん書いてきましたが、本書はテストについて解説している本ではありません。どんなコードでも自信を持って変更できるようにするための本です。本分の各章では、コードを理解し、テストで保護し、リファクタリングし、機能を追加するための手法について説明しています。
はじめ、単体テストを書くのは嫌いだった。面倒でしょうがなかった。でもモックオブジェクトに出会って以来、僕は単体テスト職人になりたいとすら思うようになっている。モックオブジェクトで依存関係を切り、仕様書をにらみ、設計書と照らし合わせながら一つずつテストケースを組み立て、そのテストはどうやってすべきか頭をひねる作業は単純に楽しいというのもある。でもそれよりも効率よくそのメソッドが、クラスが、何を意図しているのか、そしてどういう振る舞いをするのか頭の中に自信を持って組み立てていくことができるということの方が大きい。自分の行った変更が問題なかった、ほかの部分を壊していないと自信を持って言えることの方が大きい。
向かう対象が大きく複雑で汚いほどその作業は楽しいことを僕は知っている。そうやって少しずつ設計とは何かを理解できるようになる。仕様として出てくる機能の背景が気になるようになる。
きっとこれから10年、幸運にも開発者でいられたとしてもきっと僕は整然として矛盾も無駄もない世界を構築することはできないだろう。でも、その世界を理解するための道具はある。始めから終りまで迷うことなく出力することはできなかったとしても、地道にゆっくりと這い寄ることはできる。大きな手術を施すことになったとしても、正してゆくことはできる。たとえスキルが高くなくても、美しい世界を保守することはできるのだ。
*1:廃墟は破棄された。
Seleniumでテストしたページのキャプチャを撮る+画像を全部保存する
http://d.hatena.ne.jp/wonodas+dev/20121129/1354163496 の続き
前回のでもできるはできるのだが、今回の場合
- セッションが変わるとログインページに戻ってしまう
- imgのsrcに入っているタグが*.jpgなどの形式ではなくURL
file_get_contentsは新しくセッション作ってページの内容を取得するらしく、やれどもやれどもログイン画面のソースコードしか手に入らなかった。んで、しょうがないのでjavascriptを駆使することに…
あとグラフを描画させているんだが、サーバでグラフ画像作って貼り付ける形式ではなくクライアントサイドで描画させる方式のため、img src="URL"のURLで(jpg|png|gif)が含まれないことが判明(先にわかっとけ)。これを取得する方法はなさげなのでとりあえずURL表示させてキャプチャという強引な方法を取ることにしました。
※SeleniumではgetEvalまたはrunScriptでjavascriptコードを走らせることができます。
VerifyTestCase.phpに追加
<?php class PHPUnit_Extensions_VerifyTestCase extends PHPUnit_Extensions_SeleniumTestCase { //中略 //指定したURLを開いてスクリーンショットを取る(クライアントサイドで生成した画像) public function captureImageFromUrl($url, $dir = null, $fileName = null) { if($dir == null ){ $dir = __DIR__; } if($fileName == null){ $fileName = date("Ymd_His"); } $this->open($url); //余計なのをうつさないために(twitterとかね)最大化しておく $this->windowMaximize(); $this->captureScreenshotAndWait($dir . "/image" . $fileName . ".png"); } //現在のページのスクリーンショットを撮る public function captureCurrentPage($dir = null , $fileName = null){ if($dir == null ){ $dir = __DIR__; } if($fileName == null){ $fileName = date("Ymd_His"); } //余計なのをうつさないために最大化しておく $this->windowMaximize(); //file名を指定していない場合はimage-Ymd_Hisというファイル名で保存される $this->captureScreenshotAndWait($dir. "/image-". $fileName. ".png"); } //URL指定したページのイメージを取得する(jpg, gif, pngだけ) public function saveImageFromUrl($url, $dir = null) { if($dir == null) { $dir = __DIR__; } if (preg_match("/(jpg|gif|png)$/i", $url)) { //画像のファイル名で保存する file_put_contents($dir . "/" . basename($url), file_get_contents($url)); } } //ページ内の画像をすべて保存する public function saveImagesOnPage($url, $dir = null) { $this->open($url); //今表示しているページのdocumentを取得 $this->getEval("doc=this.page().getCurrentWindow().document;"); //imgタグを全部取得 $this->getEval("imageArr = Array.slice(doc.getElementsByTagName('img'));"); //imgタグがいくつあるかをimgCountに格納 $imgCount = $this->getEval("imageArr.length;"); //なかったら終わる if ($imgCount == 0) { return; } $dir = $dir === null ? __DIR__ : $dir; $dirPath = $dir . "/" . date("Ymd_His"); mkdir($dirPath); $imgUrlArr = array(); for ($i = 0; $i < $imgCount; $i++) { //imgのsrcを取得して配列に詰める //なぜかgetEval("i=0");getEval("iamgeArr[i].src");getEval("i = i+1");だと最初しか取れないのでこうした $imgUrlArr[] = $this->getEval("imageArr[" . $i . "].src;"); } //重複はのぞく $imgUrlArr = array_unique($imgUrlArr); foreach ($imgUrlArr as $index => $url) { //jpg,gif,pngだったら画像を保存、そうじゃなかったらキャプチャ(二重チェックになってるなこれ…) if (preg_match("/(jpg|gif|png)$/i", $url)) { $this->saveImageFromUrl($url, $dirPath); } else { $this->captureImageFromUrl($url, $dirPath, $index); } } } }
Seleniumで画像を取得する(キャプチャを使わない)
captureEntirePageScreenshotがfirefox以外だとうまく動かないが、firefoxはnetbeansからだとなぜか実行できないので自前でHTML内にある全ての画像を落とすようにした。どうせエビデンス取らなきゃいけないしページが長い場合はスクロールしなきゃいけないけどようわからんので画像ファイルで落とせればいいや、というかんじ。
HTMLファイル
<html> <body> <img id="smp" src="./sample.png"> </body> </html>
ひとまず画像だけが置いてあるHTML
テストファイル
なお、phpunit-seleniumを使用しております。本心としてはPHPUnit_Extensions_SeleniumTestCaseクラスを継承したPHPUnit_Extensions_VerifyTestCaseを作成して、そこにsaveImageメソッドを作成してどこでも使えるようにする。
テストケースはやっぱりテストケースで分類すべきだよなとちょっと思ったので。ホントはちゃんと名前空間柄使ったほうがいいんだろうけどめんどいので省略。
SaveImageTest.php
<?php require_once __DIR__. '/PHPUnit_Extensions_VerifyTestCase'; class indexTest extends PHPUnit_Extensions_VerifyTestCase { function setUp() { $this->setBrowser("*googlechrome C:\Program Files\Google\Chrome\Application\chrome.exe"); $this->setBrowserUrl("http://localhost/index.php"); } function testGetImage() { $this->open("http://localhost/index.php"); //assertは一個くらいいれておく $this->assertElementPresent("id=smp"); //指定したページの画像ファイルだけを保存する。第一引数がURL, 第二引数は保存するディレクトリパス $this->saveImage("http://localhost/index.php", __DIR__); $this->close(); } }
PHPUnit_Extensions_VerifyTestCase.php
ついでなのでphpUnit-Seleniumに定義されていないverifyなんとかメソッドとかもここに定義してしまおうと思っている。verifyじゃなくてcustomとかにしたほうがいいのかね。まあいいか。
<?php require_once 'PHPUnit/Extensions/SeleniumTestCase.php'; class PHPUnit_Extensions_VerifyTestCase extends PHPUnit_Extensions_SeleniumTestCase { public function saveImage($url, $dir = __DIR__){ //時間がかかる場合にタイムアウトしないように念のため0にセット set_time_limit(0); //<img ~>タグを検索 preg_match_all('/(<img+(.*?)+>)/i',file_get_contents($url), $matches); //重複を削除する $getArr = array_unique($matches[0]); foreach($getArr as $tag) { //<img ~>タグの中身をとりあえず空白で分割する $imgTagArr = explode(" ", $tag); //空白で分割したものの中からsrc="~"というのを探す foreach($imgTagArr as $item) { if(strstr($item, "src") != false){ //srcが見つかったらファイル名を取得し抜ける $path = explode("\"", $item); break; } } //画像ファイル拡張子がついているかどうかを調べる if(preg_match("/(jpg|gif|png)$/i", $path[1])) { //ファイルを取得するURLを作成し直す $urlReplacePos = strrpos($url, "/"); $urlFile = substr($url, 0, $urlReplacePos+1) . $path[1]; //保存ディレクトリ名を生成し、作る $dirPath = $dir. "/". date("Ymd_His"); mkdir($dirPath); //ファイルに書き込み file_put_contents($dirPath. "/". basename($path[1]), file_get_contents($urlFile)); } } } }
こんな感じ。
Developers summit 2012 行ってきた
devsumiねデブサミ。今年も行って来ました。
17日午前中だけなんですけどね…色々と厳しい状況だったけどJenkinsだけはききたかったので!
「Continuous DeliveryとJenkins」
概要(記憶に残ったのだけ書いとく)
- マシンの性能は上がっている。一方人の性能は変わらない→それなら自動でできることはマシンにやらせるべき
- 高性能マシンを並列化しまくったら時間もかからないしコスト削減になる
- というか時間=コストってことだもんなぁ、人月計算してる以上はと思ったりした
- 人の性能は変わらんのでコード書く速度はそんなに早くもならない(むしろ大規模になると低下したりもする?)
- 削れる時間はビルド時間、テスト実行時間→そこでCIツール
- ただCIツールを入れるだけでなにもかも解決するわけではない
- たいていはバージョン管理をしているが、サブミット(コミットとかチェックインとかツールによっていい方は様々だが要するにファイルを共有サーバに入れることだ)する前にビルドが通ること、などというルールがあったりすると、結局ローカルでビルドして直して…となってなかなかサブミットできないし、CIツールの意味がないし、ローカルの環境よりサーバのほうがスペック言いに決まっとる
- 現状でうちでもビルドと単体テストと動的メモリテストなんかはJenkinsを使っているが、基本ローカルで単体テストに通ることを確認してから入れる決まりになっている。んで、うちはC++つかってるんだが、でかいやつになるとビルドに5,6分はかかる…ちょっと直してデバッグしてビルドして…で一日かかるとかザラ
- なので、ビルドはもう完全にCIツールに任せてしまいましょう、という話だった。
- あとこれとパイプライン方式を混ぜればなんかうまいこと運用を考えられそうだ
- とりあえず思ったのは、
- コードサブミット用ブランチをひとつ作る。開発者はここにビルド成功するかどうか分かんないけどとりあえずコードをサブミットする
- Jenkinsはサブミットされたらビルドを開始する。ビルド中開発者は別の所を修正したりテストを書いたりとかしておく
- ビルドが失敗したらメールが来る。開発者は直してサブミットしなおす
- ビルドが成功したらJenkinsがテスト用ブランチにサブミットする。サブミットがあるとテスト用ブランチで自動テストが走る。失敗したら(ry)。成功したら次のブランチもしくはマスターブランチにサブミット
- 問題になりそうなのは衝突が起こった場合だな。これはやっぱり手動でしないといけないかもしれない。
- あといま、自動メモリテストのジョブが成功したら自動的にリリースビルドのジョブが走るようにしてるので、*用ブランチというのをいくつも作らんとサブミット用ブランチ一つとマスター用ブランチでよいかもしれない
- Perforce連携のプラグインてないんですかね…
「仕事のバトン、渡っていますか? - プロジェクト管理におけるコミュニケーション基盤作り」
どうしようかなーと思ったんだけど一応行ってみた。ちょうど課題管理のことは問題になってるので。ちなみにうちはRedmineをつこうております。
記憶に残ったとこだけ
- 課題管理は特に理由がないのならExcel最強
- 曖昧なトリガはチケットとしては不適当。結局グレーのまま放置される
- はっきりとしたバグとかそういうのだとチケット駆動にはしやすい
- チケットの内容は丁寧に書きましょう
- チケットは共有しているものだという意識を持ちましょう
- 計画段階切っていくチケットはよっぽど慣れていない限りあんまり有効でない。計画の段階では大抵のことは曖昧なため(もしくは曖昧なこともわからない(まぁあるあるですな
- あとツールはいくつも使うな(あるあるすぎますな
- メール、電話の内容も全部課題管理表に書きこむこと(うちはこれをバージョン管理ツールでやってしまっている
いやあ本当にまっとうなことばかりだったのですみませんという感じでした。
Wordpressではてな記法を使えるようにしてみた。
http://rewish.org/wp/hatena_notation_plugin
こういうありがたいプラグインが!
今のところ記事ごとに切り替えというのができなくて、会社ローカルで導入する際にpukiwiki記法との併用が出来なかった(pukiwikiでかくとhtmlで吐き出されてしまう)のでちょっとだけカスタマイズした。突貫工事なのであってるかどうかは不明。
wp-hatena-notation.phpにあるrender関数を
public function render($content) { $tag = '/\[hatena\](.*?)\[\/hatena\]/s'; //追加 preg_match($tag, $content, $matches); //追加 if (!isset($this)) { return self::getInstance()->render($content); } if (empty($this->option['after_enable_date']) && strstr($content, '[hatena]')) { //条件追加 return $this->_render($matches[1]); //代入文字列変更 } global $post; if ((self::df($post->post_date) > self::df($this->option['after_enable_date'])) && (strstr($content, '[hatena]')) ) { //条件追加 return $this->_render($matches[1]); //代入文字列変更 } return $content; }
とかきかえた。これで[hatena]〜[/hatena]でくくったところははてな記法になるはず――なんだけどなぜか1ポストまるまるはてな記法になるのであれ?と思っているところ。うーむ。一応記事ごとの切り替えは出来ます。
あとはxoops上のwikiをWordpressに吐き出さればいいんだが、エクスポートできないのか?プラグインどれ入れりゃいいのか全然わからん。。。
非Web屋の俺がOpen Flash Chartを使ってみた
いろいろと詰まったけど慣れてる人なら簡単に導入できると思われ。
Open Flash Chartとは
公式:http://teethgrinder.co.uk/open-flash-chart-2/
参考:http://fujitaiju.com/blog/php/open-flash-chartver2-x%E3%81%A8php%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%82%B0%E3%83%A9%E3%83%95%E3%82%92%E6%9B%B8%E3%81%8F%EF%BC%88%E5%B0%8E%E5%85%A5%E7%B7%A8%EF%BC%89/
Open Clash Chartとは、ウェブ上にFlashでグラフを描画するためのオープンソフトです。PHP, Ruby, Perl, Js< Pythonなどなどで使えるようです。DotNetもあるみたい。
仕事でwebUIをつくらんといけんくなった(デモ用)のでちょいちょいと使ってみた。
俺はWeb屋さんじゃないのでアパッチ起動するだけで一苦労です。
基本的にコンパイラのある言語しか使ったことないので、デバッグの仕方がわからNEEEE!!!
環境としてはRHEL 6.0 Enterprise 64bit, Apache2.2.18, PHP5.2.17を用意しました。エディタはしょうがない(?)のでEclipseのプラグインを導入。Windows環境だったらxamppを導入すればオールインワンのはず。CentOSだと最新版がダウンロードされないかもしれないのでyumの設定を書き換えましょう。ここでは割愛。
Apache+PHPを最新版にしよう
古いのが入っていたので最新版へ。まぁいろいろなところにいろいろなことが書いてあるので今さら俺が書いてもしょうがないかもしれんが、一応。
Apacheの最新版をダウンロードして展開、インストール
さくっとな。
ひとつ気をつけないといけないのは、たぶんRedHatに最初から入っているApacheはconfigureのオプションでlibファイルを生成するオプションが有効になっていないっぽい。なので、単に./configureとするとその後でPHPのlibphp5.soができないらしい。これで一日死んだ。
参考:http://oss.poyo.jp/pipermail/php-study/2006-October/000309.html
$ tar zxvf httpd-x.x.x.tar.gz $ cd httpd-x.x.x $ ./configure --enable-so {ほかオプション} $ make $ make install
なお、Apache2.0は/usr/local/apache2以下にファイルが展開されます(特に指定しなかった場合)。ほんでもって実行ファイルは/usr/local/apache2/bin/httpdなんだけど、それを実行するスクリプトは/usr/local/apache2/bin/apachectlらしい。
展開したフォルダ/build/httpd.initを/etc/rc.d/init.d/httpdに移動して設定を書き換えるてサービス化すると、apachectlと/etc/rc.d/init.d/httpdのスクリプトが両方叩かれて二重起動→80番ポート空いてないんですけど?って怒られる。
詳しい設定方法は詳しく書いているところがあると思うのでそちらを参照してください。
これがわからなくて一日死んだ。
PHPの最新版をダウンロードして展開、インストール
rpmがありゃ楽なんだけどなぁ。ま、さくっとな。libphp5.soファイルを作成するためにapacheのapxsが必要なようだ。
参考:http://www.oklab.org/language_c/php5_0_2_install_bug.htm
特定環境って書いてるけど、多分RedHatのapacheのオプションの設定のせいだと思われ。
$ tar zxvf php-x.x.x.tar.gz $ cd php-x.x.x $ ./configure --with-apxs2=/usr/local/apache2/bin/apxs {その他オプション} $ make $ make install $ su root find / -name libphp*
これでlibphp5.soがあればOK
libファイルを適当(適切という意味)なところへコピーして、あとはapacheを起動する。
cp /usr/local/apache2/modules/libphp5.so /usr/lib64/httpd/modules/libphp5.so service httpd start
phpinfoを実行してhttpdとphpのバージョンを調べよう。php知らない人のために書いておくと
<?php phpinfo(INFO_MODULES); ?>
というファイルを作ってデフォルトだと/var/www/html/の下に置く。なおブラウザで閲覧する場合は
http://localhost/ファイル名
としてみよう(←それすら知らないのだった
http://localhost/ = /var/www/htmlです。これはhttpd.confのDocumentRootで変更可。
Forbiddenが出てしまう場合は
参考:http://www.cyberciti.biz/faq/apache-server-status/
とりあえずDeny from allをコメントアウトしとけばよいのかしら。
ようやくOpen flash chartへ
導入はとても簡単。/var/www/html以下にファイルをダウンロードしてきて展開すれば使えます。
なおOpen flash chartはv2.xになっているにもかかわらずググるとv1.xの方が上位に表示されるので注意。
公式(こっちね):http://teethgrinder.co.uk/open-flash-chart-2/
v1.x:http://teethgrinder.co.uk/open-flash-chart/
メソッド名やプロパティなどが変わっているので互換はない模様。
基本的にはチュートリアルのとおりやっていけばOKです。open-flash-chart.swfのパスの設定を忘れそうなら、同じフォルダに配置するのが吉。
とにかくやってみる。
<html><head> <!-- グラフ表示のためのJsとフラッシュファイルを指定する --> <script type="text/javascript" src="../../ofc/js/swfobject.js"></script> <script type="text/javascript"> swfobject.embedSWF("open-flash-chart.swf", "data", "550", "200", "8.0.0", "expressInstall.swf", {"data-file":"chart_data.php"}); swfobject.embedSWF("open-flash-chart.swf", "data1", "550", "200", "8.0.0", "expressInstall.swf", {"data-file":"chart_data1.php"}); </script> </head> <body> <!-- グラフを挿入する --> <div id = "data"></div> <div id = "data1"></div> </body> </html>
いきなり二つ表示させる場合をかいてしまいましたが。
swfobject.embedSWFの引数に
- フラッシュのファイル
- グラフのnameに当たる名前
- グラフのwidth
- グラフのheight
- フラッシュのバージョン? 8.0.0または9.0.0とかいておけばよいぽい。10.0.0でもいいのかな
- 複数のファイルを表示する場合は後ろの二つの引数が必要。expressInstall.swfはようわからんがおまじない
- 最後の引数は{"data-file":"グラフに描画するデータ・グラフ設定について書いたphpファイル"}とする
ちなみに一個しか表示しないよという場合は後ろの二つの引数は省略できます。そのかわりブラウザに表示するときは
http://localhost/disp.php?ofc=chart_data.php
などとしないといけない模様。"?ofc="とかいてデータファイルを食わせるんだね。
さて、肝心のデータファイル
これもとりあえずTutorialに書いてある通りに書けばできるが一応。
<?php include 'php-ofc-library/open-flash-chart.php';//php5-ofc-libraryとしたほうがよいのかもしれない //create dammy data $data = array(); for($i = 0; $i < 10; $i++){ $data[] = $i; } //set title $title = new title("TITLE"); //set line $dot = new dot(); $dot->colour('#cd5e3c'); $line = new line(); $line->set_defaultdot_style($dot); //hoverするとドットが表示される $line->set_values($data); //データを与えてやる $line->set_width(3); $line->set_colour('#68bd8d'); //set y axis $y = new y_axis(); $y->set_range(0, 15, 3); //set chart chartを出力するとブラウザ上に表示できるようになる $chart = new open_flash_chart(); $chart->set_title($title); $chart->add_element($line); $chart->set_y_axis($y); echo $chart->toString(); ?>
chartに作った設定をくっつけてやると表示されます。結構C#ぽい実装なのでわかりやすい。
データベースからデータを取ってきて描画してみよう。
データベースはMySQLでもいいんだけど情報がないのでPostgresについて書いてみる。
表示用のPHPは大して変わらんのでそのままにしておくとして、チャートデータの方。
<?php include 'php5-ofc-library/open-flash-chart.php'; //データベースを開く postgresというユーザーでpostgresという名前のデータベースにログイン //失敗した場合はその場で死ぬ $db = pg_connect("host=localhost port=5432 dbname=postgres user=postgres password=postgres") or die("failed to connect"); //データを取ってくる $tableName = 'testdb'; $result = pg_query($db, "SELECT * from {$tableName};") or die ("faield to query\n"); //fetchで実際にデータの値が取れる $data_all = pg_fetch_all($result); pg_close($db); //連想配列のままでは描画できないので項目ごとにarrayに分ける $data1 = array(); $data2 = array(); foreach($data_all as $key=>$tmp){ $data1[] = intval($tmp['data1']); //文字列で入ってくるらしいので数字に直してやる $data2[] = intval($tmp['data2']); } if(count($data1) == 0) die('An error occurred\n'); $title = new title("TEST"); $dot = new dot(); $line = new line(); $line->set_default_dot_style($dot); $line->set_values($data1); $bar = new bar_filled('#999', '#aaa'); $bar->set_values($data2); $chart = new open_flash_chart(); $chart->set_title($title)+ $chart->add_element($bar); $chart->add_element($line); echo $chart->toPrettyString(); ?>
文字列ってところがわからなくてかなり死んだ。
ただま、出来ちゃうとすごく簡単かな。日本語ドキュメントは少ないけど公式にもソースコードが乗っているのでそんなに困らないはず。