はてなキーワード: グローバル変数とは
A Beautiful Site (http://abeautifulsite.net/)さんの
jquery.fileTreeを利用させてもらった。
以下、留意点...
パスを指定しないと、もとのhtmlがあるパス(ディレクトリ)にあるものと解釈する。
(/jqueryFileTree.php と指定すると、公開しているルートディレクトリにあるjqueryFileTree.phpを探しにいく)
http://...と指定して他のサーバへ問い合わせるのも可能な模様(だが、試していない)。
root:
d:/
d:/temp/
など
hemlentries -> htmlspecialchars は必須。
http://treatment-head.blogspot.com/2008/11/jquery-file-tree_21.html
ただし、UTF-8やEUC-JPでページを記述している場合は、さらに処理が必要。
windowsでは、mbstringの設定にかかわらず、引数SJIS渡し、戻り値SJIS返しの模様。
したがってUTF-8やEUC-JPでページを記述している場合は、
その点を考慮してconnectorsフォルダにあるjqueryFileTree.phpを書き換える必要がある。
$_POST['dir'] = urldecode($_POST['dir']);
という行があるが(スーパーグローバル変数はデコード済みで、さらにデコードするのは危険とphpマニュアルに記載されている)
どのみちUnicode文字列のURLデコードはこの関数では無理なようなので、phpマニュアルのUserNoteから拝借。
http://php.net/manual/en/function.urldecode.php
こちらにズバリが掲載されているか...と試してみたが、どうも動作がうまくいかなかった
http://ameblo.jp/pushurinko/entry-10287161493.html
他、ご参考
失礼 スコープグローバルではないので、グローバル変数というのは、語弊があるな。寿命が恒久の意味
お詫びのコード
template<typename T>
T * getT(){
static T globalMem;
return &globalMem;
}
さて・・・これって、グローバルなのかね?
ヘッダでテンプレート展開できる部分に置こうとすると、こうならねーか?グローバルな変数って。
狙ってこう使うのはいいと思うけど、あやまって、何でもかんでもstatic付けるとバグるよねぇ
//突っ込まれるかと思って、待ってたけど、やっぱり、そっちを突っ込んだかぁ・・・
関数の中に static って書くとグローバル変数になるプログラミング言語を知らないので
ぜひその言語を教えてください
あー 関数の中に static 変数名 って書くとグローバル変数になるって 知らないで 書いていてバグ出した人を知っている。
見つけたときにキレそうになった。
ポジションにもよるけど、直せるんだったら、直しとけば。で、報告すれば。ついでに直しておきましたって。
いいお客さんなら、次の仕事の単価がコッソリ、よくなる。おおっぴらにはしないけど、根切りの時の圧力が弱い。
とある大規模インフラの基幹システムなんだけど、納品して以来、誰にも原因が分からない不具合が続いていたのでした。よく品質保証部を通ったなと不思議に思ってるんですがね。
現地で動かしてみないと分からない、って奴かな?
所詮は外注が格安で作ったシステムだからこんなもんなんだろう。しかし、数年もほったらかしにしておく神経がよく分からない。
で、今回、そのシステムの改修で俺が担当プログラマーになったわけだが、組み合わせ試験をしていると、出るんだわ、この現象が。現象を見ていて再現条件を想像。結果、ある条件をそろえると100%再現。復旧させるには、リブートさせるか、ある条件を1秒以内に整えれば復旧する。
なんで「誰にも分からない」のかよく分からない。見てて動作が変だったから、LANアナライザ突っ込んでハンドシェーク見てたら仕様書通りになってねーでやんの。試験したのか?これ。
そこからスタートして、2つの小システムを行ったり来たりしながら逆に遡る事8時間。原因発見。
さて、問題は、今回の受注範囲に関係無いんだよな、これ。直すべきか、ほっとくべきか。
「次期システムでは、今まで6つに分かれていたシステムが1つに統合されます」
今思えば、この台詞が出た時点で引き返すべきだったんだと思う。
気付けば「初期値が NULL のテーブル」の隣に「基本が NOT NULL のテーブル」が鎮座していた。
各システムから引き継がれた COBOL の遺産が、システムを跨いで好き勝手に DB アクセスしていた。
今まで疎結合を保っていたシステムが、DB という名前のグローバル変数を介して密結合となった。
DAO みたいな生易しい思想なんて無い、全てのプログラムが DB への自由なアクセスを許された世界。
既に DB の内容を保証してくれるモジュールは無くなった。誰も一貫性を保証してなどいない。
当然バグも頻発する。バグ票の起票数は 3000 を超えた。全部 EXCEL 管理なのが憎さに拍車をかけている。
もうそろそろ駄目だと思うけど、誰も「やめよう」なんて言ってくれないのが一番辛い。
あれは私がまだ大学助手をしていたころだから3年ほど前のことだと思う。
私の勤めていた大学(情報系)では「プログラミング研究会」みたいなサークル活動が行われていて
プログラミングの講義を受け持っていた私はそのサークルにちょくちょく顔を見せるようになっていた。
そこにはとびっきりかわいい女子学生が一人いたのだけれど、その子はゲームが大好きで
「自分でもゲームが作りたい」と一念発起してゲームコンテストに作品を出品することになった。
しかし、彼女はプログラミングの講義(Java)を1年くらい受けているものの、
本格的なモノを作った経験がなく、ひとりでは行き詰まりをみせているようだった。
彼女はひとりでいることが多く、パソコンに向かって黙々とプログラムを書いているのをよく見かけた。
それを気にかけていた私はたまに彼女をランチに誘うようになり、彼女の方もしだいに私に打ち解けてきた。
私たちはだんだんと仲良くなっていった。私は彼女のキュートな笑顔に魅了されていった。
ある日、彼女が私のもとにやってきて、もじもじと顔を赤らめながら上目づかいにこう言った。
「先生、頼みごとがあるんですけど・・・」
「なんだい?」
これから恋の話が始まるのを期待したあなたは別のページを読んだ方がいいかもしれない。
これから始まるのはプログラミングの話だ。
その日から毎日のように彼女は私にメッセンジャーでプログラミングの相談を投げかけてきた。
彼女は大変優秀で、私の教えるプログラミングテクニックをみるみる吸収していった。
私は彼女の才能に驚き、彼女が将来優秀なプログラマになるであろうことを確信した。
しかし、ときおり彼女が優秀であるがゆえの面白い逆行現象が起こったのだった。
ある日、私は彼女がメモリを意識してプログラミングをしていないことに気づいた。
Java ではメモリを意識する場面というのは少ないが、まったく無いわけではない。
私は彼女にプログラムがメモリを無駄に使っているということを指摘した。
しかし、よく聞いてみると、彼女はメモリ=ハードディスクくらいの感覚しか持っていないことがわかった。
驚かないでほしい。
私の経験上、情報学部の学生の半分以上がメモリとハードディスクの区別がついていない。
それを知っている私は落胆することもなく、落ち着いて彼女にメモリの説明をすることができた。
彼女は私の説明を聞き「よくわかりました」と、とびきりキュートな笑顔を見せた。
しかし、翌日、彼女の書いたコードを見てがく然とした。コードが次のように変更されていたのである。
for (int i = 0; i < MAXHOGE; i++) {
doSomething(i);
}
for (int i = 0; i < MAXFUGA; i++) {
doSomething2(i);
}
↓
int i;
for (i = 0; i < MAXHOGE; i++) {
doSomething(i);
}
for (i = 0; i < MAXFUGA; i++) {
doSomething2(i);
}
彼女はこのコードを私に見せながら、相変わらずのキュートな笑顔でこう言った。
「このほうが使うメモリが少ないですよね!」
ゲームコンテストの締め切りが近くなってきて、実際彼女はよく頑張っていたのだが、
どうしても間に合いそうになかったので、私もコード書きを手伝うことになった。
とある部分を書いていたとき、重複したコードを見つけたので Template Method パターンを使って書き直した。
Template Method パターンというのが何かというと、同じことをするコードがいくつもの場所でばらばらに書かれないように
一つのクラスにだけ書いて、それを継承して使いまわすという手法(デザインパターンの一つ)だ。
私はこの手法を彼女に教えようとは思わなかった。
なぜなら、彼女は継承だとか委譲だとかポリモーフィズムとかがよくわかってないのだ。
驚かないでほしい。
私の経験上、情報学部の学生の99%が、その、ポリホーなんとかが分かってない。
しかし、彼女はそれに気づいていた。
彼女は私のコードを自分で解析し、新たなる発見を独力でしていた。
重複したコードがあればそれを徹底して継承で解決しようとしている。
そう、差分プログラミングだ。
差分プログラミングの正式な定義は知らないが、彼女は IS-A 関係のない継承を使ってしらみつぶしに
重複コードを書き直していた。
そのコードを見せながら、天使のような笑顔で彼女はこう言った。
「こうするとコードの量が減りますよね!」
私がこの文章で言いたいことは、知の高速道路を渡ってきた若い優秀なプログラマは
ときおり妙な退行現象を起こすということだ。
それは普通の道を通ってきた古い世代にとっては実にみょうちきりんなことに思えるかもしれない。
しかし、それは彼らなりに理由があってのことであり、馬鹿だからやってるわけではない。
彼らは優秀であるがゆえにそういったことを起こすのだ。
そして彼らは優秀であるがゆえに、自分が間違っていることを理解するのも速い。
もし、あなたのまわりで若いプログラマが逆行現象を起こすのに遭遇したとしても、
どうか暖かく見守ってほしい。
上で紹介した2件に関しては、彼女にはそのあと説明をして理解を得ることができた。
しかし我々はそれで油断してはならない。
いつか彼女はその可愛らしい顔をにっこりとほほ笑ませながらこう言うかもしれないのだ。
一時変数は数学風に短くする流儀もあるから、それに比べれば省略なんてマシな方だろ。
グローバル変数についちゃ省略する流儀は廃れてる。
基本的には、終了条件があって、
になると思うんだよね。
この二つから、反復しながら、何が変わってるのか、どう対象範囲が変化してるか、が分かれば、大まかなところはつかめるんじゃないだろうか。
あと、デバッガ使うと分かりやすいんじゃないだろうか。
中途半端に優秀なプログラマが「正しいプログラミングテクニック」だと妄信しがちな3つポイント
ちょっと囓っただけの素人が自分を過信して陥る三つの罠?
d:id:fromdusktildawn:20081026さんは「共通化とか抽象化ができるようになった中途半端に優秀な』人を対象にしているのに対して、d:id:JavaBlack:20081026さんは『ちょっと齧っただけの素人』を対象(元記事に対してかもしれない)にしているので、適用対象のレベルがそれぞれ違う気もするけど。
d:id:JavaBlack:20081026さんの記事に対するブクマコメントの幾つかやトラックバック先において、『Java屋らしい』との書き込みがあるけれど、具体的に『Java屋らしい』とはどんなことを指すのでしょう?
当方嫌われ者のエンタープライズ開発withJavaな人間ですが、Javaがよく使われるエンタープライズ向け開発などを行っていると、プログラミングは企業入ってから覚えました、っていう人の方がマジョリティだから、こういう“プログラミングのセオリー”のようなものは知る機会がないと言っていい。よほどいい先輩に当たらないと、こういうことすら教えてくれないことの方が多い。
プログラマなら自分で調べて当然、という意見もあるだろうけど、上記“マジョリティ”の彼らは、自宅でコーディングなんてするはずがないし、早くコーディングなんて卒業したい、と考えている人種。
そんな人たちは、こういうことを『知らない』し、『知ろう』とも思っていない。
そういう現場にとっては、
とある程度型にはめて指導することは、とりあえず『最低限のレベル』を守るためには有効だと思うのだけれど。まぁ元記事では『中途半端に優秀な』とわざわざ断っているから、こういうことを最低限知っていて、杓子定規になんでもかんでも共通化したりローカル変数ばっかり使っている人に対しての進言なんだろうとは思いますが。
『Java屋らしい』とは、Javaが静的型付け言語だけに、なんでもかんでも「こうしなければいけない、ならない」と断定してしまう点を指して『堅い(硬い?)』ことを言っているのでしょうか?
あと、『Java屋は長ーいメソッド名が見やすいと感じるらしい』というコメントについては、Java屋がCOBOLerに対して、
なんて書くのは冗長だよなー。とか、xx区分みたいな項目が横並びに何十項目もあるRDBなんて作るんじゃねぇ、とか思う心理と似たようなものなんでしょうか。
そもそもJavaがこんなにdisられるようになったそもそもの理由も知りたい。
教えてLLな人。
COBOLにもローカル変数やサブルーチンの引数はあるんだけど、それを使っちゃいけない企業文化で育った結果、他の言語でもその慣習を押し通したコードを書き続ける人が多いみたい。要はCOBOL以外の言語を勉強してないだけなんだけど。
業務経歴書にCOBOLって書いてあったら書類で不採用…ってしちゃった方が面接に使う時間を減らせて楽そうとも思うんだけど、「それ明らかに偏見・理不尽だろ」って自分ツッコミが入っるのでそれはやってないんだよね。
でも実際問題今までにお会いした「COBOLから業界に入った人」はみんなこんな感じで、ウチでは採用できない確率100%なんだよなあ。求む!偏見を覆せるCOBOLer!なんつってな。普通にまともにプログラムが書ける人ならCOBOL歴の有無なんかどうでもいいです。むしろ業務経験の有無すらどうでもいい。
配属から4か月が経ち、担当する制御を移ることになった。
今の制御での最後の仕事は、先輩が作った2つの関数のプログラムチェックリストの作成だった。
グローバル変数だらけで、何のための関数なのかも分らず、関数の仕様書もない。
質問しに行くと仕様書を見せられて意味を説明されたが、具体的に何の値が入れば正しいかは分からなかった。
それでも自分なりに出来る限りリストを作り、提出の日になった。
「うーん‥‥‥そうか‥‥‥
‥‥‥ネタばらしをするとな、実はこの関数って、前にお前がチェック
をしたことがある関数とほとんど同じなんだよ。」
自席に戻り、今までにやったチェックリストとソースコードを漁る。
あった。
1件につき数十個の変数や配列の値を確認しなければいけない巨大なリスト。
実際は未実装やバグで件数の半分もまともに動作しなかったものだ。
しかしチェック完了の日付は7月末 ‥‥ 右も左も分からない頃だ。
当然関数の内容なんて理解していないし、覚えてもいない。
「だから、先週お前に任せた時点で、『これ前にも見た関数だ』って気付いて、
腹が痛くなった。
別のOJTの先輩は「その作らせ方には問題がありますよ」と言ってくれたが、
「中途半端で移るのはよくない。」とのことで、結局自分が週末までに作ることになった。
制御の移動もリストの完成まで延期になった。
結局の所問題は何も解決していない。
元ネタが見つかったのは二つのうち一つ‥‥
その後の残業中に、腹痛が吐き気に変わってきたので8時過ぎに早退した。晩飯は無理っぽい‥
追記:
http://anond.hatelabo.jp/20080909191957
前回がたったひと月前なのに随分昔のようだ。
OJTを全くせず、プログラムの単体テストばかりさせているのがいけなかったらしい。
ただ俺のお向かいの席で怒るのはやめて欲しい‥‥丸聞こえでこっちまで惨めになる。
就職氷河期の真っ只中に入った会社は従業員数一桁のソフトハウス。
大学生のころバイトでシミュレーターを作っていたり、趣味でゲームを組んでいた僕はすぐに採用になった。
事業内容はあまり気にしなかった。
プログラムを組めればなんでもよかった。
最初は社内でスタディという名の研修?をやった。
簡単なプログラムを組んで、「ああ、簡単に仕事ってできるんだな」と思った。
数週間たったころ、あるプロジェクトに会社の先輩と2人でアサインされた。
やったことのないUNIXプログラミングだった。会社にはUNIXはない。開発環境もない。
そして他の会社の人から仕様を聞いて、モノを作るのも初めてだった。
まだ僕が客先に行くことができないので、先輩が話を聞いてきて、いろいろな指示をする形で仕事が進んでいった。
だけど、仕様がわからない。
客にメールを投げて聞いても、客自体も協力会社なのでわからない。
というように、俗に言う孫受けというモノだった。
元受にメールを投げているうちに、ウチの会社の質問は記憶のかなたに消えていった。
確か、「仕様がわかるまでソースを読んで現状を把握しといて」というようなことを客に言われた気がする。
そしてソースを自社に持ち帰り、読んでいたのだが、もともとがどんなプログラムなのかもわからないため、非常に難航する。
なんといっても、main関数だけで数千行のソースもあるのだ。グローバル変数もたくさん使っている。
学生のころから読んでいた
C++基礎講座 http://www.amazon.co.jp/gp/product/4844313088/
C++実用講座 http://www.amazon.co.jp/gp/product/4844313096/
にも、main関数は短めに、グローバル変数も極力使わないように。と書いてあるのに。
そして、ソースの変更場所を客先に説明するため、変更点を全て列挙してソースをWordに貼り付けて色をつけるのだ。
無駄な作業だった。
今考えるとsvn or vss or cvs使えばいいじゃない、って思う。
前の60行テンプレートエンジンを改良して、レイアウトテンプレート機能を追加してみた(それでも全部で90行)。
レイアウトテンプレート機能とは、例えば個別のテンプレートが<table>...</table>を出力して、それをレイアウトテンプレートが<html><body>...</body></html>で囲って出力するとかそんなの。
詳しくは終わりの方のサンプルをみてくれ。
これは Ruby on Rails(とその仲間たち)にある便利機能のひとつ。
ついでにいうとSmartyにはない機能のひとつ。
今まで知らなかった人はぜひ試してくれ。チョー便利だから。
前回はたくさんのブックマークありがと。
コメントで「男前テンプレート」と名前がついてたので、勝手に採用。
あと、これ以上の機能追加はしないので、各自勝手に改造して使ってくれ(そのためにコメントをつけてるから)。何でも人任せにするな。
コード:
<?php /* * OtokomaeTemplate.php -- レイアウトテンプレートに対応した90行のテンプレートエンジン * * - レイアウトテンプレート中で echo $_content; とすると中身が表示される。 * - テンプレート中で設定した変数をレイアウトテンプレートで使うことが可能。 * - レイアウトテンプレート名をテンプレート側で指定することも可能。 * - 使い方: * require_once('OtokomaeTemplate.php'); * $TEMPLATE_DIR = 'templates'; // 省略可、パーミッションに注意 * $LAYOUT_TEMPLATE = 'layout.php'; // 省略可 * $context = array('title'=>'Example', * 'list'=>array(10,'<A&B>',NULL)); * include_template('template.php', $context); * - 要 PHP 5.1 or later * - ライセンス: public domain (自由に改造してね) */ /* * 設定用のグローバル変数 */ $TEMPLATE_DIR = NULL; /* テンプレートを探すディレクトリ */ $LAYOUT_TEMPLATE = NULL; /* レイアウトテンプレートのファイル名 */ /* * テンプレートを読み込んで実行する。 * $_context は変数名をキー、値を要素とする連想配列。 * $_layout はレイアウトテンプレートのファイル名。 * - NULL または省略した場合は $LAYOUT_TEMPLATE を使う。 * - FALSE ならレイアウトテンプレートを使わない。 * - $_context['_layout'] = '...'; とすればテンプレート側でも指定可能。 */ function include_template($_filename, $_context, $_layout=NULL) { global $LAYOUT_TEMPLATE; $_content = render_template($_filename, $_context); if (@$_context['_layout'] !== NULL) // テンプレート側で指定された場合は $_layout = $_context['_layout']; // それを使う。 elseif ($_layout === NULL) // 引数で指定されなかった場合は $_layout = $LAYOUT_TEMPLATE; // デフォルトのファイル名を使う。 if ($_layout) { $_context['_content'] = $_content; // レイアウトテンプレート中で使う変数 $_content = render_template($_layout, $_context); } echo $_content; // or return $_content; } /* * テンプレートを読み込んで実行し、その結果を文字列で返す。 * include_template() の実体。 */ function render_template($_filename, &$_context) { $_cachename = convert_template($_filename); extract($_context); // 連想配列をローカル変数に展開 ob_start(); include($_cachename); // テンプレートを読み込んで実行 return ob_get_clean(); } /* * テンプレートファイルを読み込み、convert_string() で置換してから * キャッシュファイルに書き込む。読み込み時のロックは省略。 * (file_get_contents() もファイルロックできるようにしてほしいなあ。) */ function convert_template($filename) { global $TEMPLATE_DIR; if (! file_exists($filename) && $TEMPLATE_DIR) $filename = "$TEMPLATE_DIR/$filename"; $cachename = $filename . '.cache'; if (! file_exists($cachename) || filemtime($cachename) < filemtime($filename)) { $s = file_get_contents($filename); $s = convert_string($s); file_put_contents($cachename, $s, LOCK_EX); // LOCK_EX サポートは 5.1.0 から } return $cachename; } /* * テンプレートの中身を置換する。 * - '#{...}' を 'echo ...;' に置換 * - '%{...}' を 'echo htmlspecialchars(...);' に置換 * - ついでにXML宣言も置換 */ function convert_string($s) { $s = preg_replace('/^<\?xml/', '<<?php ?>?xml', $s); $s = preg_replace('/#\{(.*?)\}/', '<?php echo $1; ?>', $s); $s = preg_replace('/%\{(.*?)\}/', '<?php echo htmlspecialchars($1); ?>', $s); return $s; } ?>
<?php require_once('OtokomaeTemplate.php'); $TEMPLATE_DIR = 'templates'; $LAYOUT_TEMPLATE = 'layout.php'; $context = array('list'=>array(10,'<A&B>',NULL)); include_template('template.php', $context); ?>
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <body> <h1>%{$title}</h1> <div id="maincontent"> <!-- テンプレートの内容 --> <?php echo $_content; ?> <!-- /テンプレートの内容 --> </div> </body> </html>
<?php // レイアウトテンプレート名をテンプレート中で指定する場合 ?> <?php //$_context['_layout'] = 'mylayout.php'; ?> <?php // レイアウトで使用する変数をテンプレート中で指定する場合 ?> <?php $_context['title'] = 'レイアウトのサンプル'; ?> <table> <?php foreach ($list as $i=>$item): ?> <tr bgcolor="#{$i % 2 ? '#FFCCCC' : '#CCCCFF'}"> <td>#{$i}</td> <td>%{$item}</td> </tr> <?php endforeach ?> </table>
出力例:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <body> <h1>レイアウトのサンプル</h1> <div id="maincontent"> <!-- テンプレートの内容 --> <table> <tr bgcolor="#CCCCFF"> <td>0</td> <td>10</td> </tr> <tr bgcolor="#FFCCCC"> <td>1</td> <td><A&B></td> </tr> <tr bgcolor="#CCCCFF"> <td>2</td> <td></td> </tr> </table> <!-- /テンプレートの内容 --> </div> </body> </html>
いくつか補足:
唐突にClass::Data::Inheritableのソースコードについて説明してやんよ。
使い方とかの説明はこの辺でも読んでから出直して来い、ごるぁ!
まぁとりあえずソース見てみろ、下記にはっつけてやっからよぉ!
1: package Class::Data::Inheritable; 2: 3: use strict qw(vars subs); 4: use vars qw($VERSION); 6: $VERSION = '0.06'; 7: 8: sub mk_classdata { 9: my ($declaredclass, $attribute, $data) = @_; 10: 11: if( ref $declaredclass ) { 12: require Carp; 13: Carp::croak("mk_classdata() is a class method, not an object method"); 14: } 15: 16: my $accessor = sub { 17: my $wantclass = ref($_[0]) || $_[0]; 18: 19: return $wantclass->mk_classdata($attribute)->(@_) 20: if @_>1 && $wantclass ne $declaredclass; 21: 22: $data = $_[1] if @_>1; 23: return $data; 24: }; 25: 26: my $alias = "_${attribute}_accessor"; 27: *{$declaredclass.'::'.$attribute} = $accessor; 28: *{$declaredclass.'::'.$alias} = $accessor; 29: } 30: 31: 1;
短いソースだなーこれ。でもな、なめんじゃねーぞ。短いけど色々な技術が盛り込まれてんだよコレはよぉ。
ハイ、まず3行目。
かるくstrictについて説明してやんよ。心して聞けよオマエラ。
strictっつーのはだな、つまりPerlにおける曖昧な部分をすこーしだけチェックしてくれるスグレモノなんだなコレが。
とりあえずざっくり言うと三つの機能があってだな、下記のよーに書くわけだ。
use strict 'vars'; use strict 'subs'; use strict 'refs';
varsってーのは簡単に言うとmyとかourとか宣言しろボケってやつですわ。
subsは裸体は許さんってやつですの、$とか%とかついていない裸の文字列をエラーにしてくれんだよ。
refsってのが一番やっかいな代物でな、これはムツカシイ言葉で言うとシンボリックリファレンスってんだが、要は変数名に変数を使うとエラーにしてくれるってこったよ。
で、これら全部ひっくるめてuse strict;なんだな。わかったか?オラ!
ちゅーことはだ、3行目を見ると意図的にrefsだけ外してるのがわかるよな。
つまりコレはこのコードのどこかで変数名に変数を使うってことを明示していることにもなるわけだ。けけけ。
あーもういいもういい、次だ、次。
4,5行目を見てみろよ。今時our使わずにuse vars使うなんてどんだけー。
ははは、まぁまてよ。
ourってのは明示的にグローバル変数を定義するもんなんだが、このourってやつが導入されたのがPerl5.6からなんだよ。
Perl5.5のころはourなんてなかったからグローバル変数定義すんのにこのuse varsを使っていたわけだ。
つまりこのモジュールはPerl5.5環境でも動くように配慮しているわけなんだな、ちゃんちゃん。ほほほ。
あーもう全然すすまねーよ。チクショウ、が、ま・・・・。
で、11-14行目。これはref関数使って$declaredclassがオブジェクトだったら死ぬって処理だ。
require CarpっつーのはCarpモジュールを動的にロードしてるっていうことだよぅ。
で、Carp::croak関数使ってエラー文はいて死ぬ、と。ちなみにこのCarp::croakってはまぁdie関数みたいなもんなんだ。
違いとしてはエラーの発生した原因を呼び出し元の奴のせいにして自分は悪くないんだよってアピールすることかな。まぁ実際使ってみりゃわかるよ。
さぁ、16行目。本編突入だ。長かった。長い道のりだったなお前ら。
sub {}ってのは無名サブルーチン(関数のリファレンス)ってやつだ。で、ここで注目すべき点はただひとつ!!!!!
19-23行目あたりをぼーっとみてると$declaredclass, $attribute, $dataっていう変数を使用していることがわかる。
これらの変数は9行目で受け取ったmk_classdataへの引数だ。
ここで問題が発生する。
myで宣言された変数の賞味期限はスコープの終端だ。それはわかるな?
つまり9行目で宣言された$declaredclass, $attribute, $dataといった変数どもは29行目のスコープの終端で消滅してしまうわけだ。
しかし!その消えてしまうはずの変数どもをsub {}という無名サブルーチンの中で使用してしまっている!!!
これが世間一般に語られているクロージャという仕組みなのだ!!!!!!うはははははははh!!!
本来生涯をまっとうするはずだった変数たちが別のサブルーチンの中にまぎれてしまうとその別のサブルーチンが消えてなくなるまでは死ぬことを許されなくなるのである!!!ざ・不☆老☆不☆死!
なんたる奇妙奇天烈なことであるが、この現実を受け入れることによってお前らの道が開けるんだ!!!すげーだろぉがよぉ!!
ボクはッ、キミがッ、クロージャを受け入れるまでッ、殴るのをやめないッ!
さて、肝心の16-24行目のアクセサ部分の処理の解説だけども、
引数が渡されてなければ特になんの処理もせずに$dataを返している。$dataってのは死ぬことを許されなくなったカワイソウな変数君だ。
つまり、Class::Data::Inheritableってやつはアクセサに渡された値をどこで保存してるのかというと、紛れも無いこの$data君に他ならない。
$data君がニート君になっちゃうとたちまちデータの読み書きができなくなるのであまり働かせ過ぎないように注意しよーね!
ハイ、次はアクセサに引数が渡された時の処理だけどな、20行目を見てみろ。$declaredclassに格納されてる値はmk_classdataメソッドを使用したときに格納された値になる。
package Hoge; use base qw/Class::Data::Inheritable/; Hoge->mk_classdata('hoge_accessor');
つまり上記の処理で例えると、$declaredclassには'Hoge'という文字列が入ってることになんだな。
で、この'Hoge'と$wantclassに入ってる値を比較しているわけだが、
package Hoge; use base qw/Class::Data::Inheritable/; Hoge->mk_classdata('hoge_accessor'); Hoge->hoge_accessor('aaa');
上記の処理で例えると$wantclassには$declaredclassと同じく'Hoge'が入ってくることになんだな。うっひょー。
んで、20行目のif文は$wantclassと$declaredclasが違う場合にだけ19行目の処理を実行しているわけだからこの場合はスルーするわけだぁ。ひょひょひょ。
じゃあだな、$wantclassと$declaredclasが違う場合ってどんな場合?ってことだが、下記に例を示すから目ん玉引ん剥いて網膜から直接見てみろよこのボケ野郎どもが。
package Hoge; use base qw/Class::Data::Inheritable/; Hoge->mk_classdata('hoge_accessor'); package Foo; use base qw/Hoge/; Foo->hoge_accessor('bbb');
HA!HA!HA!こういう場合だよ米ベー。$wantclass=Fooで$declaredclas=Hogeになるんで19行を実行し、Fooをベースにしてmk_classdataを呼ぶことでFooに同じ名前の新たなアクセサを提供し、元クラスHogeの値を壊さないようにするわけですなぁ。
考えた人すごいですなぁ。これがClass::Data::Inheritableが継承可能なクラス変数といわれる由縁でするまする。
で、最後の26-28行目はコレらの便利な処理をしてくれる$accessorさんをクラスに登録するというわけですよぉ。
27,28行目の*ってのは型グロブ変数ってという奴で、型グロブに対して無名サブルーチンを突っ込むと動的に関数を定義できるんだなぁコレが。
でここで、初めに俺が語った話を覚えてるか?へっ、オマエラなら覚えてないだろうなけっけ。use strictの話だよ。refsだよrefs。
ここでrefsを省いていたのが利いて来るんだ。refsって何だった?ホラ言ってミソ?
で良く見てみると型グロブ変数に対して「$declaredclass.'::'.$attribute」っていう変数を使おうとしているよね?これをしたかったからrefsだけ仲間外れにしてたわけですね。
はは。
あー、あー、あー。
これで終わりだよぅ。みんなわかったかな!?
コレ読んでもわからんやつはもう死ぬか、もしくはわからん用語について死ぬほど調べてもっかい読みなおしてみろこのド低のぅッ・・・ごふんごふん、このクサレ脳みそがぁ!!!!!!!!!!!!11
増田に職業プログラマっぽいのが、結構な割合で居そうなのが判った。
そして自分も楽しめた。ありがとう。
こういう話大好き。
こうやってみんなのスタイル見ると、どのスタイルも大して見づらい事もないんだよね。
でも実際の引継ぎ仕事やら、全面改修やらで回ってくるソースって、ありえない事になっちゃってる率があまりに高いよね。
ああいう、訳の判らない事態に陥る原因とかがやんわり判ったりすると、ちょっと面白いのかもなぁって思った。
例として、過去に自分が死にかけた(と言うかぶちきれて、仕事放り投げたくなった)ソース
・関数が10個程度しかない
・関数一つ当たりの行数が1万越え
・内switch文が占める割合9割
おまえはBASICか(いや、basicでももっとましだけど)と突っ込みたくなった。
用はswitch文一つ一つが関数の役割を果たしてて、それをグローバル変数一つで切り替えて制御していると言う…言っててむなしくなってきた。