tag:crieit.net,2005:https://crieit.net/tags/%E9%9B%91%E8%A8%98/feed 「雑記」の記事 - Crieit Crieitでタグ「雑記」に投稿された最近の記事 2019-10-28T00:15:55+09:00 https://crieit.net/tags/%E9%9B%91%E8%A8%98/feed tag:crieit.net,2005:PublicArticle/15512 2019-10-27T23:39:10+09:00 2019-10-28T00:15:55+09:00 https://crieit.net/posts/The-Zen-of-Python The Zen of Python 邦訳 <h2 id="The Zen of Python"><a href="#The+Zen+of+Python">The Zen of Python</a></h2> <p>って知ってますか?</p> <p>知らないっていう人は、Pythonインタプリタを立ち上げて、<code>import this</code>しましょう。</p> <blockquote> <p>The Zen of Python, by Tim Peters</p> <p>Beautiful is better than ugly.<br /> Explicit is better than implicit.<br /> Simple is better than complex.<br /> Complex is better than complicated.<br /> Flat is better than nested.<br /> Sparse is better than dense.<br /> Readability counts.<br /> Special cases aren't special enough to break the rules.<br /> Although practicality beats purity.<br /> Errors should never pass silently.<br /> Unless explicitly silenced.<br /> In the face of ambiguity, refuse the temptation to guess.<br /> There should be one-- and preferably only one --obvious way to do it.<br /> Although that way may not be obvious at first unless you're Dutch.<br /> Now is better than never.<br /> Although never is often better than <em>right</em> now.<br /> If the implementation is hard to explain, it's a bad idea.<br /> If the implementation is easy to explain, it may be a good idea.<br /> Namespaces are one honking great idea -- let's do more of those!</p> </blockquote> <p>こんな感じのやつ。<br /> 何番煎じかわからないけれど、邦訳してみます。</p> <h2 id="The Zen of Python, by Tim Peters 日本語訳版"><a href="#The+Zen+of+Python%2C+by+Tim+Peters+%E6%97%A5%E6%9C%AC%E8%AA%9E%E8%A8%B3%E7%89%88">The Zen of Python, by Tim Peters 日本語訳版</a></h2> <ol> <li>醜いよりは美しい方がいい。</li> <li>暗黙よりは明示の方がいい。</li> <li>複雑よりも単純な方がいい。それでも、ワケわからなくなるよか複雑な方ががマシ。</li> <li>ネストするよりフラットな方がいい。</li> <li>詰め込んであるよりも空白が多い方がいい。</li> <li>読みやすさは重要だ。</li> <li>特別な場合であっても、ルールを破るに足る特別な理由にはならない。しかしながら、純粋さよりは実用性の方が大事。</li> <li>エラーを無視してはいけない。明示的に握り潰すなら別だけれども。</li> <li>曖昧さを前にして、推測で済まそうとしてはいけない。</li> <li>あることをする明白な方法が1つあり、しかも1つしかないのが好ましい。あなたがオランダ人でもない限り、はじめは明白には思えないにしても。</li> <li>やらないよりは今やった方がいい。とはいえ、やらない方が今すぐやるよりもいいことはしばしばある。</li> <li>実装を説明するのが難しいなら、それは悪いアイデアだろう。もし、実装を説明するのが簡単なら、それは良いアイデアかもしれない。</li> <li>名前空間は1つのとてもいい考え。そういうのをもっとやろう!</li> </ol> <p>ゆるっとしたコーディングや設計に関する指針で、結構ためになります。The Zen of Pythonという名前ですが、Python以外でもこの考え方は通用します。</p> <p>初心を忘れないためにも、時々<code>import this</code>するのはいいアイデアなのではないでしょうか?</p> <h2 id="そういえば"><a href="#%E3%81%9D%E3%81%86%E3%81%84%E3%81%88%E3%81%B0">そういえば</a></h2> <p><code>this.s</code>という変数にこの文章が入っています。</p> <pre><code class="python">s = """Gur Mra bs Clguba, ol Gvz Crgref Ornhgvshy vf orggre guna htyl. Rkcyvpvg vf orggre guna vzcyvpvg. Fvzcyr vf orggre guna pbzcyrk. Pbzcyrk vf orggre guna pbzcyvpngrq. Syng vf orggre guna arfgrq. Fcnefr vf orggre guna qrafr. Ernqnovyvgl pbhagf. Fcrpvny pnfrf nera'g fcrpvny rabhtu gb oernx gur ehyrf. Nygubhtu cenpgvpnyvgl orngf chevgl. Reebef fubhyq arire cnff fvyragyl. Hayrff rkcyvpvgyl fvyraprq. Va gur snpr bs nzovthvgl, ershfr gur grzcgngvba gb thrff. Gurer fubhyq or bar-- naq cersrenoyl bayl bar --boivbhf jnl gb qb vg. Nygubhtu gung jnl znl abg or boivbhf ng svefg hayrff lbh'er Qhgpu. Abj vf orggre guna arire. Nygubhtu arire vf bsgra orggre guna *evtug* abj. Vs gur vzcyrzragngvba vf uneq gb rkcynva, vg'f n onq vqrn. Vs gur vzcyrzragngvba vf rnfl gb rkcynva, vg znl or n tbbq vqrn. Anzrfcnprf ner bar ubaxvat terng vqrn -- yrg'f qb zber bs gubfr!""" </code></pre> <p>いわゆる換字式暗号ってやつですね。換字表は<code>this.d</code>で得られます。</p> <pre><code class="python">d = {'A': 'N', 'B': 'O', 'C': 'P', 'D': 'Q', 'E': 'R', 'F': 'S', 'G': 'T', 'H': 'U', 'I': 'V', 'J': 'W', 'K': 'X', 'L': 'Y', 'M': 'Z', 'N': 'A', 'O': 'B', 'P': 'C', 'Q': 'D', 'R': 'E', 'S': 'F', 'T': 'G', 'U': 'H', 'V': 'I', 'W': 'J', 'X': 'K', 'Y': 'L', 'Z': 'M', 'a': 'n', 'b': 'o', 'c': 'p', 'd': 'q', 'e': 'r', 'f': 's', 'g': 't', 'h': 'u', 'i': 'v', 'j': 'w', 'k': 'x', 'l': 'y', 'm': 'z', 'n': 'a', 'o': 'b', 'p': 'c', 'q': 'd', 'r': 'e', 's': 'f', 't': 'g', 'u': 'h', 'v': 'i', 'w': 'j', 'x': 'k', 'y': 'l', 'z': 'm'} </code></pre> <p>そこで、この暗号を復号するプログラムをPythonで書いてみてください。<br /> <code>sys.stdout</code>を<code>io.StringIO</code>とかに差し替えてから<code>import this</code>は復号プログラムを書いたとは言いませんよ。</p> <h3 id="正答例"><a href="#%E6%AD%A3%E7%AD%94%E4%BE%8B">正答例</a></h3> <pre><code class="python">print(''.join(map(lambda x: this.d.get(x, x), this.s))) </code></pre> frodo821 tag:crieit.net,2005:PublicArticle/15498 2019-10-22T16:42:46+09:00 2019-10-22T17:08:45+09:00 https://crieit.net/posts/SNS-URL ドメイン殺しにやられた話。SNS時代の外部URL遷移は超キケン <p>先日、長いこと閉鎖していたサービスを復活させました。</p> <p><strong>OGP changer</strong><br /> <a target="_blank" rel="nofollow noopener" href="https://ogpc.ga/">https://ogpc.ga/</a></p> <p>これは、SNS共有用のURLを発行するサービスです。閉鎖に至ったのには大きな理由がありました。</p> <h1 id="短縮URLサービスのドメインを殺された"><a href="#%E7%9F%AD%E7%B8%AEURL%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%AE%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%92%E6%AE%BA%E3%81%95%E3%82%8C%E3%81%9F">短縮URLサービスのドメインを殺された</a></h1> <p>きっかけは<a target="_blank" rel="nofollow noopener" href="https://splamp.info/">弊サイト</a>が管理する別の短縮URLサービス「URL Shortener」(<a target="_blank" rel="nofollow noopener" href="https://lmp.tw">lmp.tw</a>)の悪用でした。</p> <p>URL Shortenerは純粋な短縮URLサービスです。ユーザー数が少ないため、他よりも短いURLを取得できるのがウリでした。</p> <p>ところが。</p> <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">短縮URLサービスでテロられたこんなことあるんか</p>— ウラル (@barley_ural) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/barley_ural/status/1116611726206627844?ref_src=twsrc%5Etfw">April 12, 2019</a></blockquote> <p>まさかの事態に。</p> <h2 id="何が起きたのか?"><a href="#%E4%BD%95%E3%81%8C%E8%B5%B7%E3%81%8D%E3%81%9F%E3%81%AE%E3%81%8B%EF%BC%9F">何が起きたのか?</a></h2> <p>lmp.twドメインが全てTwitterに弾かれ、一切ツイートできないようになっていました。既にツイートされたリンクを踏むと、全てのページでセキュリティエラーが表示されるようになりました。<br /> 一言でいうと、<strong>ブラックリストに登録された</strong>のです。</p> <p><img src="https://pbs.twimg.com/media/D38RHjhVUAAX00G?format=jpg&name=medium" alt="image" /></p> <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">危険なサイトへのリダイレクトを作られてしまって、そのせいで短縮URLサービスのドメイン丸ごとTwitterに弾かれてる他のリンクも全部ブラックリスト扱いされてる…</p>— ウラル (@barley_ural) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/barley_ural/status/1116612307151245319?ref_src=twsrc%5Etfw">April 12, 2019</a></blockquote> <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">経緯を説明すると、lmp. tw配下全てのリンクに警告表示が出ることを発見→危険なサイトにリダイレクトさせるツイートが投稿されていた→直ちに該当ツイートのリンクの無効化と管理する全てのURLリダイレクトサービス新規登録を停止 <a target="_blank" rel="nofollow noopener" href="https://t.co/ZsERui2Jp2">pic.twitter.com/ZsERui2Jp2</a></p>— ウラル (@barley_ural) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/barley_ural/status/1116630154342572034?ref_src=twsrc%5Etfw">April 12, 2019</a></blockquote> <p>この人物は、lmp.twの他にも複数の短縮URLサービスで危険なリンクを作成し、ツイートすることで、サービスを殺しているようでした。悪意があるとしか言いようがありません。</p> <p><a href="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5dae73e69bd42.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5dae73e69bd42.png?mw=700" alt="image.png" /></a></p> <p>これまでも数多くの短縮URLサービスが出来ては消えていきましたが、このような悪意ある利用がその主な原因だったと言えるでしょう。</p> <p>私はすぐにサービスを停止せざるを得ませんでした。そして、同様のリスクがある以上、他のURLリダイレクトサービスも動かすわけにはいかず、OGP changer(<a target="_blank" rel="nofollow noopener" href="https://ogpc.ga/">ogpc.ga</a>)も停止することになったのでした。</p> <h2 id="ドメインを取り戻すまで"><a href="#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%92%E5%8F%96%E3%82%8A%E6%88%BB%E3%81%99%E3%81%BE%E3%81%A7">ドメインを取り戻すまで</a></h2> <p>lmp.twがブラックリスト入りしたことで、私のTwitterアカウントのプロフィールのリンクが使えなくなりました。</p> <p><a href="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5dae7a6d335a5.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5dae7a6d335a5.png?mw=700" alt="image.png" /></a></p> <p>これでは信用に関わります。泣く泣くリンクを削除しましたが、このまま放置するわけにはいきません。危険なリンクは既に削除したので、まずはドメインを回復させます。</p> <p>危険なURLと判断された流れは次の通りでしょう。</p> <ol> <li>元々「Google Safe Browsing」(URL安全性確認サービス)によって危険と判断されていたURLを、悪意のあるユーザーが短縮URLサービスに登録し、ツイートする。</li> <li>GoogleによってURLが認識され、Google Safe Browsingでドメイン全体に危険ステータスが付与される。</li> <li>Twitterや他のセキュリティサービスがその情報を元にドメイン全体をブロックする。</li> </ol> <p>ですから、まずはGoogle Safe Browsingによるスパム判定を解除する必要があります。</p> <p><img src="https://pbs.twimg.com/media/D38RHjhU8AASaw8?format=jpg&name=medium" alt="image" /></p> <p>サイトが危険と見なされているかどうかは<a target="_blank" rel="nofollow noopener" href="https://transparencyreport.google.com/safe-browsing/search"><strong>このページ</strong></a>から確認できます。</p> <p><a href="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5daea6e72e057.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5daea6e72e057.png?mw=700" alt="image.png" /></a></p> <p>Google Safe Browsingに再審査を要求する手順は<a target="_blank" rel="nofollow noopener" href="https://developers.google.com/web/fundamentals/security/hacked/request_review"><strong>こちら</strong></a>です。<br /> 審査に合格するとステータスが解除されます。</p> <p>Google Safe Browsingによるステータスが解除され次第、マカフィーなど他のセキュリティサービスの解除申請を送ると良いでしょう。</p> <p>Twitterでは、「<a target="_blank" rel="nofollow noopener" href="https://help.twitter.com/forms/spam"><strong>スパムを報告</strong></a>」というページから、「Twitterがスパムと判断したため、リンクをツイートできません。」を選ぶことで、スパム判定を食らったリンクを回復できます。</p> <p><a href="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5dae7d48c419b.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5dae7d48c419b.png?mw=700" alt="image.png" /></a></p> <p>色々やった結果、lmp.tw自体は数週間で回復しました。<br /> 信用を失うのは一瞬だが、取り戻すのは本当に手間と時間がかかる、と実感しました。</p> <h1 id="対策"><a href="#%E5%AF%BE%E7%AD%96">対策</a></h1> <p><a target="_blank" rel="nofollow noopener" href="https://ogpc.ga/">OGP changer</a>はそんなわけで、同様のリスクがある以上復活させられないことから、長い間「改修中」と称し閉鎖していました。<br /> ちなみにずっと404を返していたところ、ドメイン管理サービスに「使用実態がない」と見なされ、ドメインを剥奪されるハプニングもありました…。</p> <h2 id="Safe Browsing APIの利用"><a href="#Safe+Browsing+API%E3%81%AE%E5%88%A9%E7%94%A8">Safe Browsing APIの利用</a></h2> <p>Google Safe Browsingによって弾かれたのですから、同じ基準で守ればよいのです。<br /> GoogleのSafe Browsing APIを使うと、そのリンクが安全かどうかを判定できます。</p> <p>こちらのブログを参考に、PHPでURLの判定を行なうようにしました。</p> <blockquote> <p>サイトの安全性を確かめるSafe Browsing APIをPHPで試す<br /> <a target="_blank" rel="nofollow noopener" href="https://minory.org/safe-browsing-api.html">https://minory.org/safe-browsing-api.html</a></p> </blockquote> <p>APIキーなどはGoogle Cloud Platformでプロジェクトを作成して取得します。</p> <h1 id="感想"><a href="#%E6%84%9F%E6%83%B3">感想</a></h1> <p>外部へのURL遷移には今後注意していこうと思いました。無意味な遷移はできるだけ控えたほうがよいでしょう。もしサービスの中で外部URL遷移を利用している場合は、何かしらの対策を行うべきです。<br /> Safe Browsing APIの利用の他、HTTPのLocationによる遷移ではなく、HTMLのmetaタグによる遷移や、javascriptによる遷移に変更するのも良いでしょう。<br /> まだまだ自分の知らないセキュリティリスクは多いなと感じました。</p> <p>最後に、半年ぶりに復活を果たした<a target="_blank" rel="nofollow noopener" href="https://ogpc.ga/">OGP changer</a>をよろしくお願いします。</p> <p><a href="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5daeb2e276daf.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5daeb2e276daf.png?mw=700" alt="image.png" /></a></p> ウラル tag:crieit.net,2005:PublicArticle/15398 2019-09-16T00:18:49+09:00 2019-09-16T00:30:47+09:00 https://crieit.net/posts/0ad3fb07d90d16ac9612cde5d92f6bed オブジェクト指向とは何だったのか(初心者として) <p>極度の面倒くさがりにより、漠然とオブジェクト指向から距離を置いてきたが、最近初めて触れ、やっと理解できた気がするので書く。</p> <p>世の人間はオブジェクト指向を説明するとき、たい焼きだの設計図だの何だのと言い始める。<br /> そうじゃないんだ。読めるようになりたいんだ。</p> <p>ということで、自分なりにまとめてみる。PHPを例にする。誰かの役に立てたら嬉しい。</p> <h1 id="オブジェクトって何"><a href="#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%A3%E3%81%A6%E4%BD%95">オブジェクトって何</a></h1> <p>まず、「オブジェクト指向」とはそもそも何かと言うと、設計思想の1つのことだ。<br /> そしてこのオブジェクト指向を実現するため、「クラス構文」という書式がある。要はこれが使えればいいのだ。</p> <p><a href="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5d7cecde17e98.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5d7cecde17e98.png?mw=700" alt="image.png" /></a></p> <p>「オブジェクト」とは関数と変数のカタマリの事である。関数と変数が梱包された状態だと思ってほしい。</p> <p><a href="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5d7ceecf2278b.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5d7ceecf2278b.png?mw=700" alt="image.png" /></a></p> <p>このオブジェクトのことを「クラス」とも呼ぶ。「クラス構文」とは、つまりオブジェクトを定義する書式だと思えばいい。</p> <p style="font-size:smaller;margin:0;padding:0;">※わかりやすくするため、ここでは「オブジェクト」=「クラス」とする。後述する「インスタンス」はオブジェクトと呼ばれやすいが、クラスとは別物。「オブジェクト」=関数と変数のカタマリの総称、「クラス」=オブジェクトを定義したもの、「インスタンス」=クラスをインスタンス化したもの、なんだなーと思っておけば大丈夫。</p> <h1 id="オブジェクトを使っていく流れ"><a href="#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%84%E3%81%8F%E6%B5%81%E3%82%8C">オブジェクトを使っていく流れ</a></h1> <p>オブジェクトは定義して呼び出すのが基本で、こういう流れになる。</p> <p><strong>【定義する】</strong></p> <p>空っぽのオブジェクトを用意する。<br /> ⇓<br /> オブジェクトの中に変数や関数を入れていく。<br /> ⇓<br /> オブジェクトが定義できた!(オブジェクト完成!)</p> <p><strong>【呼び出す】</strong></p> <p>定義されたオブジェクトを読み込む。<br /> ⇓<br /> オブジェクトから変数や関数を引っ張りだして使う。</p> <h1 id="オブジェクトの中身を呼び出すには"><a href="#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E4%B8%AD%E8%BA%AB%E3%82%92%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%99%E3%81%AB%E3%81%AF">オブジェクトの中身を呼び出すには</a></h1> <p>オブジェクトは、中身の呼び出し方を考えてから定義することが多いので、先に呼び出し方を確認しておこう。</p> <h2 id="例"><a href="#%E4%BE%8B">例</a></h2> <p>例として、引数に与えた文字をそのまま表示するユーザー定義関数<code>foo()</code>を用意した。</p> <pre><code class="php">function foo($str) { echo $str; } </code></pre> <p>この関数を、どんな名前でもいいが、ここでは<code>MyProject</code>という名前のオブジェクトに入れることにする。(「オブジェクトを定義するには」で手順は後述)<br /> 早速オブジェクト<code>MyProject</code>から<code>foo()</code>を呼び出してみる。</p> <pre><code class="php">// 事前にオブジェクトが定義されているとする $obj = new MyProject; $obj->foo('おはよう!'); // おはよう!が表示される </code></pre> <p>最初の行を見てほしい。<br /> <code>$obj</code>という変数の中に、オブジェクトが代入されている。</p> <p>そう、オブジェクトは<code>new 〇〇</code>という書式で、変数に一度代入することで使えるようになる。これを「インスタンス化」と呼び、このとき、変数は「オブジェクト型」という状態になっている。</p> <p>つまり、上記の例ではオブジェクト型の変数<code>$obj</code>に、事前に定義したオブジェクト<code>MyProject</code>の中身がそのまま入っているのだ。</p> <p><a href="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5d7d037044f18.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5d7d037044f18.png?mw=700" alt="image.png" /></a></p> <p>この代入された変数のことを「インスタンス」という。インスタンス=オブジェクト型の変数のことである。</p> <p>続きを見てほしい。<br /> <code>$obj->foo('おはよう!')</code>とある。これは、オブジェクトのインスタンスから<code>foo()</code>というユーザー定義関数を呼び出している。</p> <p><a href="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5d7d072b8b744.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5d7d072b8b744.png?mw=700" alt="image.png" /></a></p> <p>このとき、普通の関数とは呼び出し方が異なるので、この関数のことを特別に「メソッド」と呼ぶ。</p> <p>やたら用語ばかり出てきて申し訳ない。先ほどのコードはこういうことである。<br /> <a href="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5d7e3c4152609.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5d7e3c4152609.png?mw=700" alt="image.png" /></a></p> <h1 id="オブジェクトを定義するには"><a href="#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%92%E5%AE%9A%E7%BE%A9%E3%81%99%E3%82%8B%E3%81%AB%E3%81%AF">オブジェクトを定義するには</a></h1> <p>さて、ここで先ほどの例で使ったオブジェクト<code>MyProject</code>を定義する手順だ。</p> <p>最初に空っぽのオブジェクトを用意する。こう書く。</p> <pre><code class="php">class MyProject { } </code></pre> <p>この中にさっき作ったユーザー定義関数<code>foo()</code>を入れてみると…</p> <pre><code class="php">class MyProject { function foo($str) { echo $str; } } </code></pre> <p>オブジェクトが完成!<br /> これだけ?これだけ!<br /> これで、<code>MyProject</code>というオブジェクトの中に<code>foo()</code>というメソッドが定義されたことになる。</p> <p>さっき呼び出しの部分で書いたものと組み合わせてみよう。</p> <pre><code class="php">class MyProject { function foo($str) { echo $str; } } $obj = new MyProject; $obj->foo('おはよう!'); // おはよう!が表示される </code></pre> <p>これで一段落。これが理解できたあなたは、とても基本的なクラス構文をマスターしたことになる。</p> <h1 id="オブジェクトにしかできないこと…プロパティ"><a href="#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AB%E3%81%97%E3%81%8B%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%E3%81%93%E3%81%A8%E2%80%A6%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3">オブジェクトにしかできないこと…プロパティ</a></h1> <p>ここまで来た人は疑問に思うかもしれない。<br /> 「関数をメソッドにする意味って何なの?」「それ、ユーザー定義関数で良くね?」と。</p> <p>ここからは、オブジェクト指向だからできること、プロパティの仕組みを説明する。</p> <p>「オブジェクトって何?」で説明した図を思い出してほしい。</p> <p><a href="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5d7ceecf2278b.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/f37dd84b36bcbac2749ed7d9d5d7127f5d7ceecf2278b.png?mw=700" alt="image.png" /></a></p> <p>そう、梱包されてるのは関数(メソッド)だけじゃなかった。変数もいた。<br /> このオブジェクトの中で定義された変数のことを、「プロパティ」と呼ぶ。</p> <p>プロパティの基本的な定義の仕方と呼び出し方は次の通り。</p> <pre><code class="php">class MyProject { public $text = 'おはよう!'; // これがプロパティ } $obj = new MyProject; echo $obj->text; // プロパティの呼び出し </code></pre> <p>メソッドと似ていることがわかるだろうか?<br /> そう、プロパティとメソッドは扱い方がとてもよく似ている。</p> <p>今回は、最初に少し見慣れないキーワード「public」について説明しよう。<br /> これは、メソッド(関数)やプロパティ(変数)のアクセス権を示している。<br /> PHPではpublic, protected, privateの3つがある。</p> <div class="table-responsive"><table> <thead> <tr> <th>アクセス権</th> <th>範囲</th> </tr> </thead> <tbody> <tr> <td>public</td> <td>オブジェクトの外部から呼び出せる。継承されたオブジェクトから呼び出せる。オブジェクト内のメソッドから呼び出せる。</td> </tr> <tr> <td>protected</td> <td>オブジェクトの外部から呼び出せない。継承されたオブジェクトから呼び出せる。オブジェクト内のメソッドから呼び出せる。</td> </tr> <tr> <td>private</td> <td>オブジェクトの外部から呼び出せない。継承されたオブジェクトから呼び出せない。オブジェクト内のメソッドから呼び出せる。</td> </tr> </tbody> </table></div> <p>プロパティではこれらのアクセス権を必ず明示する必要がある。メソッドでは、省略した場合publicとしてみなされる。<br /> つまり、前項の例で作ったメソッドは、publicを省略していたということだ。省略できるのだが、アクセス権はちゃんと書いておいたほうが喜ばれるだろう。</p> <p>さて、プロパティで注意してほしいのは、メソッドの外でないと宣言できないということだ。<br /> 例えば、以下のようなことはできない。</p> <pre><code class="php">class MyProject { // publicなメソッドを宣言 public function foo() { public $text = 'おはよう!'; // メソッド内なのでエラー echo $text; } } $obj = new MyProject; echo $obj->foo(); </code></pre> <p>これは、ユーザー定義関数の特性上、その中で使われる変数はローカルスコープでないといけないからだ。<br /> もしメソッドの中でプロパティを使いたいのなら、<code>$obj->text</code>みたいな感じで変数を呼び出さなければならない。だが、自分のオブジェクトの中で自分のオブジェクトを指定するのもおかしいよな…ということで、擬似変数<code>$this</code>が登場する。</p> <pre><code class="php">class MyProject { public $text = 'おはよう!'; public function foo() { echo $this->text; // $thisは自分自身を表す } } $obj = new MyProject; echo $obj->foo(); // おはよう! </code></pre> <p><code>$this</code>を使うと、プロパティを活かして、例えばこんなことができる。</p> <h2 id="カートに商品を追加する例"><a href="#%E3%82%AB%E3%83%BC%E3%83%88%E3%81%AB%E5%95%86%E5%93%81%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%E4%BE%8B">カートに商品を追加する例</a></h2> <pre><code class="php">class Cart { protected $quantities = []; // 商品ごとの量が入る public function add($product, $quantity) { $this->quantities[$product] = $quantity; } public function get_quantity($product) { return $product . 'は' . $this->quantities[$product] . '個'; } } $my_cart = new Cart; $my_cart->add('バター', 1); $my_cart->add('牛乳', 3); $my_cart->add('卵', 6); echo $my_cart->get_quantity('牛乳'); // 牛乳は3個 </code></pre> <p>合計金額を表示するメソッドも作れる。</p> <pre><code class="php">class Cart { protected $prices = [ 'バター' => 600, '牛乳' => 180, '卵' => 200, 'アイス' => 100 ]; protected $quantities = []; public function add($product, $quantity) { if(isset($this->prices[$product])) { $this->quantities[$product] = $quantity; } } public function get_quantity($product) { return $product . 'は' . $this->quantities[$product] . '個'; } public function get_total_price() { $total_price = 0; foreach($this->quantities as $key => $quantity) { $total_price += $this->prices[$key] * $quantity; } return $total_price; } } $my_cart = new Cart; $my_cart->add('バター', 1); $my_cart->add('牛乳', 3); $my_cart->add('卵', 6); echo $my_cart->get_total_price() . '円'; // 2340円 </code></pre> <p>オブジェクト指向の便利さはここからだ。上の例の後半だけ次のように書き換える。</p> <pre><code class="php">$cart1 = new Cart; $cart1->add('バター', 1); $cart1->add('バター', 3); $cart1->add('卵', 6); $cart1->add('卵', -3); $cart2 = new Cart; $cart2->add('アイス', 2); $cart2->add('牛乳', 1); echo $cart1->get_total_price() . '円'; // 1200円 echo $cart2->get_total_price() . '円'; // 380円 </code></pre> <p>インスタンス<code>$cart1</code>, <code>$cart2</code>が別々のものとして計算されている。つまり、2つのオブジェクトは独立して動作しているのだ。</p> <p>これがインスタンス化の最大のメリットである。もしこの処理をユーザー定義関数で無理やり実現しようとすると、それぞれの処理が複雑に干渉してしまい、たちまち地獄が訪れるだろう。</p> <p>処理をいい感じに独立させることは、プログラミングをする上でとても大切だ。また、プログラムに将来への拡張性があることも、どれほど大切かわかる人は多いだろう。</p> <p>オブジェクト指向はこれを実現するためにある。<br /> インスタンス化で複数の機能をいい感じに独立させられる。またクラスの中にメソッドを追加しても他の処理に影響を与えないため、将来への拡張性も確保できる。</p> <h1 id="おわりに"><a href="#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB">おわりに</a></h1> <p>オブジェクト指向はプログラマの「あったらいいな」が詰め込まれているため、機能が多すぎて面食らってしまいやすいが、本質的な部分はとても簡単なものである。<br /> 継承や無名関数、コンストラクタなど、面白い機能が他にもたくさんあるので、興味があるものから一つずつ調べてみるのがいいだろう。</p> <h1 id="PHPマニュアルおすすめ部分"><a href="#PHP%E3%83%9E%E3%83%8B%E3%83%A5%E3%82%A2%E3%83%AB%E3%81%8A%E3%81%99%E3%81%99%E3%82%81%E9%83%A8%E5%88%86">PHPマニュアルおすすめ部分</a></h1> <p><a target="_blank" rel="nofollow noopener" href="https://www.php.net/manual/ja/language.oop5.basic.php">PHP: クラスの基礎</a></p> <p><a target="_blank" rel="nofollow noopener" href="https://www.php.net/manual/ja/language.oop5.properties.php">PHP: プロパティ</a></p> <p><a target="_blank" rel="nofollow noopener" href="https://www.php.net/manual/ja/language.oop5.visibility.php">PHP: アクセス権</a></p> <p><a target="_blank" rel="nofollow noopener" href="https://www.php.net/manual/ja/functions.anonymous.php">PHP: 無名関数</a></p> ウラル tag:crieit.net,2005:PublicArticle/14922 2019-04-12T23:52:08+09:00 2019-04-13T09:28:16+09:00 https://crieit.net/posts/43f728e8f7dd291fac74e6d34aa15409 障害が起きたときに誰が謝るのかという問題(社内サービス編) <p>今は社内の開発者向けにサービス開発をしていて、まぁまぁの人数に使ってもらっている。で、サービスはまだまだ発展途上なので、リリースしてからもたまにシステムメンテナンスなどを行うことがある。まぁそんな感じでちょいちょい本番系をイジることがあるわけだけど、今日はそのメンテナンスをきっかけに障害が発生した。</p> <p>ここで問題なのは障害が発生したことではなくて(もちろん障害それ自体は問題なのだけど)、障害をどうハンドリングするかっていうこと。ここで言うハンドリングというのは、</p> <ol> <li>障害を調査し、解決すること</li> <li>障害を拡大させないために作業を指示すること</li> <li>障害の内容を利用者に説明すること</li> </ol> <p>通常、これらをすべてうまくこなせるのは障害を起こした本人だったりする(もちろんそれなりに技術や知識があることを必要とする)。であるならば、障害を起こした人はどの作業に専念すべきだろうか?これは当然#1である。次に#2で、#3。ということで、対応の優先度は上から順番に行うべき。</p> <p>とはいえ、実際のところ、それなりにいるユーザーたちからは苦情が上がってくるわけで、障害内容を説明しなければならない。で、この説明を考えるのはそれなりに難しい。もちろん嘘をつくのはダメだけど、とはいえ、どこまで内容を詳らかにするか。そして、正確に問題を説明できるのも障害を起こした本人。そして、なぜ#2を行わなければならないのかを説明できるのも障害を起こした本人。</p> <p>こんな感じであらゆることが障害を起こした本人にのしかかってくる。ここでようやく本題に入るわけなんだけど、一番やりたくない(というか、やる必要性が無い)し、面倒なのは、問題を説明し謝ることじゃないかなと思う。それに、当事者が謝るべきという考え方だと失敗を責める文化ができてしまって挑戦的な試みができなくなる組織になる。</p> <p>で、じゃあ他に誰が謝るのかということになる。謝るためには事態を正確に把握し、理解する必要があるけど、実際には無理。解決しようとする人を捕まえて、理解できるまで逐一説明させるとか自己満足でしかない。なので、(良い意味で)ごまかしが出来るセンスが必要になる。自分にはそういった感じのセンスがあるかなと思ってたけど、結局最後には障害を起こした本人に謝らせることになってしまった。まぁそれは本人が自主的にそうしたから、そうなったんだけど最後までちゃんと謝ることができなくて、ふがいないなーと思ったっていう、ただそれだけのために1000文字ぐらいをここに書いた。</p> shige