diff options
| author | nsfisis <nsfisis@gmail.com> | 2022-11-19 14:23:32 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2022-11-19 14:25:59 +0900 |
| commit | 6209453817da9922f28bac1bb1522c6d380630ab (patch) | |
| tree | 19e0699e751af387d549d6720ca215c8065b3c0c /docs/tags | |
| parent | 0cafa073914b5e0b162b735a7f8445fb2aa8a604 (diff) | |
| download | blog.nsfisis.dev-6209453817da9922f28bac1bb1522c6d380630ab.tar.gz blog.nsfisis.dev-6209453817da9922f28bac1bb1522c6d380630ab.tar.zst blog.nsfisis.dev-6209453817da9922f28bac1bb1522c6d380630ab.zip | |
Hugo to Asciidoctor
Diffstat (limited to 'docs/tags')
45 files changed, 0 insertions, 5942 deletions
diff --git a/docs/tags/conference/feed.xml b/docs/tags/conference/feed.xml deleted file mode 100644 index f536cbb..0000000 --- a/docs/tags/conference/feed.xml +++ /dev/null @@ -1,944 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> - <channel> - <title>conference on REPL: Rest-Eat-Program Loop</title> - <link>https://blog.nsfisis.dev/tags/conference/</link> - <description>Recent content in conference on REPL: Rest-Eat-Program Loop</description> - <generator>Hugo -- gohugo.io</generator> - <language>ja-JP</language> - <lastBuildDate>Sat, 27 Aug 2022 18:55:28 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/conference/feed.xml" rel="self" type="application/rss+xml" /> - <item> - <title>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</title> - <link>https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/</link> - <pubDate>Sat, 27 Aug 2022 18:55:28 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/</guid> - <description><![CDATA[ <h1 id="はじめに">はじめに</h1> -<p>本日 <a href="https://phpcon.okinawa.jp/">PHP カンファレンス沖縄 2022</a> が開催された (らしい)。</p> -<p>カンファレンスには参加できなかったものの、懇親会の LT で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。</p> -<p>ツイート: <a href="https://twitter.com/m3m0r7/status/1563397620231712772">https://twitter.com/m3m0r7/status/1563397620231712772</a> <br> -スライド: <a href="https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3">https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3</a></p> -<h1 id="解">解</h1> -<p>細かいレギュレーションは不明だったので、勝手に定めた。</p> -<ul> -<li>コマンドライン引数の第1引数で受けとる</li> -<li>結果は標準出力に出す</li> -<li>コンマの直後にはスペースを1つ置く</li> -<li>末尾コンマは禁止</li> -<li>数字でないものは入ってこないものとする</li> -<li>負数は入ってこないものとする</li> -</ul> -<p>書いたものがこちら:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>[<span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> $n<span style="color:#f92672">=</span>$argv[<span style="color:#ae81ff">1</span>];<span style="color:#66d9ef">foreach</span>([<span style="color:#ae81ff">1e4</span>,<span style="color:#ae81ff">5e3</span>,<span style="color:#ae81ff">2e3</span>,<span style="color:#ae81ff">1e3</span>,<span style="color:#ae81ff">500</span>,<span style="color:#ae81ff">100</span>,<span style="color:#ae81ff">50</span>,<span style="color:#ae81ff">10</span>,<span style="color:#ae81ff">5</span>,<span style="color:#ae81ff">1</span>]<span style="color:#66d9ef">as</span>$x)<span style="color:#66d9ef">for</span>(;$n<span style="color:#f92672">>=</span>$x;$n<span style="color:#f92672">-=</span>$x)$r[]<span style="color:#f92672">=</span>$x;<span style="color:#66d9ef">echo</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">', '</span>,$r<span style="color:#f92672">??</span>[]);<span style="color:#75715e">?></span><span style="color:#960050;background-color:#1e0010">] -</span></span></span></code></pre></div><p>しめて 123 バイトとなった (末尾改行を含めずにカウント)。</p> -<p>こちらは改行とスペースを追加したバージョン:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>[<span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$n <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>]; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ([<span style="color:#ae81ff">1e4</span>, <span style="color:#ae81ff">5e3</span>, <span style="color:#ae81ff">2e3</span>, <span style="color:#ae81ff">1e3</span>, <span style="color:#ae81ff">500</span>, <span style="color:#ae81ff">100</span>, <span style="color:#ae81ff">50</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">1</span>] <span style="color:#66d9ef">as</span> $x) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> (; $n <span style="color:#f92672">>=</span> $x; $n <span style="color:#f92672">-=</span> $x) -</span></span><span style="display:flex;"><span> $r[] <span style="color:#f92672">=</span> $x; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">', '</span>, $r <span style="color:#f92672">??</span> []); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">?></span><span style="color:#960050;background-color:#1e0010">] -</span></span></span></code></pre></div><h1 id="使用したテクニック">使用したテクニック</h1> -<h2 id="指数表記">指数表記</h2> -<p>割と多くの言語のゴルフで使えるテクニック。<code>e</code> を用いた指数表記で、大きな数を短く表す。このコードでは <code>10000</code>、<code>5000</code>、<code>2000</code>、<code>1000</code> を指数表記している。</p> -<h2 id="foreach-や-for-の中身を1つの文に">foreach や for の中身を1つの文に</h2> -<p><code>foreach</code>、<code>for</code>、<code>if</code> などの後ろには、通常 <code>{</code> を続けて複数の文を連ねるが、中身の文を1つにしてしまえば、<code>{</code> と <code>}</code> を省略できる。C言語などでも使える。</p> -<h2 id="r-に初期値を入れない">$r に初期値を入れない</h2> -<p>PHP では、<code>$r[] = ...</code> のような配列の末尾に追加する式を実行したとき、<code>$r</code> が未定義だった場合は <code>$r</code> を勝手に定義して空の配列で初期化してくれる。これを利用すると、<code>$r = [];</code> のような初期化が不要になる。</p> -<p>ただし、プログラムに 0 が渡されるとループを一度も回らないので、<code>$r</code> が未定義になってしまい、<code>implode()</code> に渡すところでエラーになる。それを防ぐために <code>$r ?? []</code> を使っている。</p> -<p>もし 0 が渡されたケースを無視するなら、これが不要になるので 4 バイト縮む。</p> -<h2 id="php-タグの外に文字列を置く">PHP タグの外に文字列を置く</h2> -<p>PHP では、<code><?php</code> <code>?></code> で囲われた部分の外側にある文字列は、そのまま出力される。今回のケースでは、先頭と末尾に必ず <code>[</code> と <code>]</code> を出力するので、そのまま書いてやればよい。</p> -<h1 id="おわりに">おわりに</h1> -<p>最後になりましたが、<a href="https://twitter.com/m3m0r7">めもりー</a> さん、楽しい問題をありがとうございました。</p> -]]></description> - </item> - - <item> - <title>PHPerKaigi 2022</title> - <link>https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/</link> - <pubDate>Sun, 01 May 2022 09:41:39 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/</guid> - <description><![CDATA[ <h1 id="はじめに">はじめに</h1> -<p>2022-04-09 から 2022-04-11 にかけて開催された、<a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> に、一般参加者として参加した。 -弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p> -<p>昨年のレポートは<a href="/posts/2021-03-30/phperkaigi-2021">こちら</a>。</p> -<h1 id="感想">感想</h1> -<h2 id="厳選おすすめトーク">厳選おすすめトーク</h2> -<p>多くの素晴らしいトークの中から、特におすすめのものを 5つ選んだ。是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。</p> -<p><a href="https://fortee.jp/phperkaigi-2022/proposal/ef8cf4ed-63fe-42f8-8145-b3e70054458b">予防に勝る防御なし - 堅牢なコードを導く様々な設計のヒント</a></p> -<blockquote> -<p>PHP はバージョンを追う毎に型宣言、例外、表明、列挙型などの機能が大幅に強化され、堅牢なコードを書くための機能が充実してきました。それらの機能はどう使うと効果的なのでしょうか。</p> -<p>本講演では PHP 8.1 をベースにして、誤りを想定してチェックするのではなく、そもそも誤りにくい設計とはどのようなものか、つまり「予防」の観点を軸足に、堅牢なコードを導くための様々な設計のヒントをご紹介します。</p> -</blockquote> -<p><a href="https://fortee.jp/phperkaigi-2022/proposal/db00d49e-0dd6-453f-b54b-f731d112f10e">PHPのエラーを理解して適切なエラーハンドリングを学ぼう</a></p> -<blockquote> -<p>PHPを使ってるとよく遭遇する Fatal error / Parse error / Warning / Notice 理解していますか?<br> -これらのエラー文を理解することで、すぐにエラーの原因に気付き適切に対象できる様になります!<br> -またそれらを理解した上でのエラーハンドリングを学びましょう。</p> -</blockquote> -<p><a href="https://fortee.jp/phperkaigi-2022/proposal/4a7e3ded-9134-4919-955c-ec7bf4491c0d">エラー監視とテスト体制への改善作戦</a></p> -<blockquote> -<p>毎日流れてくるエラーに皆さんはどう向き合ってますか?<br> -エラーを出さない事が一番ですが、完全に塞ぐ事は難しいと考えます。<br> -サービス運用の中で本番環境から発生するエラー(サーバー・クライアントサイド・サードパーティ起因のエラー)への監視体制と、<br> -エラー・バグ防御のためチームで行っているテストコード文化づくりの話をします。</p> -</blockquote> -<p><a href="https://fortee.jp/phperkaigi-2022/proposal/6f47daf8-c78f-4fb1-9b99-e9656e6fe7f7">ISUCON11のPHP実装は、何を考え、どのようにして作られていたのか</a></p> -<blockquote> -<p>昨年開催されたISUCON11にて問題(参考実装)のPHPへの移植を担当させていただきました。</p> -<p>最終的なソースコードこそシンプルなWebアプリケーションではありますが、その裏には<br> -・「(私の思う)良い設計」を実現するための意思決定<br> -・「ISUCONの問題」という位置付けに由来する取捨選択<br> -・移植中に遭遇したトラブルとその解決策<br> -といった文脈や葛藤が存在しています。</p> -<p>本発表はそれらを共有することで<br> -・PHPアプリケーションの設計、実装事例として役立ててもらう<br> -・ISUCONの言語移植に興味を持ってもらう<br> -・ISUCON問題移植の「実装や設計の練習をする教材」としての可能性を知ってもらう<br> -ことを目的とします。</p> -</blockquote> -<p><a href="https://fortee.jp/phperkaigi-2022/proposal/5a260e4e-542d-4d82-849d-ef3d6cb7c854">チームの仕事はまわっていたけど、メンバーはそれぞれモヤモヤを抱えていた話──40名の大規模開発チームで1on1ログを公開してみた</a></p> -<blockquote> -<p>サイボウズの大企業向けグループウェアのGaroon(ガルーン)は、PHPで開発されている20年目の製品です。ガルーン開発チームは日本で40名、ベトナムで50名の計90名ほどのチームになっています。また、コロナ禍でフルリモートでの活動がこの2年ほど継続してきました。</p> -<p>フルリモートになっても仕事はまわっており、継続的にリリースはしていましたが、一方でお互いの考えていることや感じている問題意識が見えづらくなり、モヤモヤを抱えているメンバーが増えていました。</p> -<p>このセッションでは、そういう状況で私がチーム外からジョインし、聴き役に徹しながら見える化することで状況を改善していった取り組みを紹介します。同じように大きなチームやリモートワークで難しさを感じている人に、難しさの原因への気づきや取り組みへのヒントがあれば幸いです。</p> -</blockquote> -<h2 id="トークン問題の作成">トークン問題の作成</h2> -<p>今回は、PHPer チャレンジ用に弊社のトークン問題を 3題作成した。こちらについては<a href="/posts/2022-04-09/phperkaigi-2022-tokens">別途記事にしている</a>ので、そちらを参照されたい。</p> -<h2 id="phper-チャレンジ">PHPer チャレンジ</h2> -<p><a href="https://fortee.jp/phperkaigi-2022/challenge">1位</a>になった。<br> -また、賞品として <a href="https://www.amazon.co.jp/dp/B08MQNJC9Z">Echo Show 15</a> をいただいた。</p> -<h2 id="カンファレンス全体への感想">カンファレンス全体への感想</h2> -<p><a href="/posts/2021-03-30/phperkaigi-2021">去年の参加レポ</a> では、こんなことを書いた。</p> -<blockquote> -<p>1つ個人的な反省点としては、(中略) Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。<br> -まあ初カンファレンスだし、とお茶を濁しておこう。</p> -</blockquote> -<p>この反省を踏まえ、今年は積極的にほかの場 (公式の Discord サーバや、アンカンファレンス) にも参加した。<br> -これにより、参加体験の質がはるかに向上した。特に Discord に関しては、登壇者ご本人による補足や、質問への回答などがおこなわれる (ことが多い) ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。</p> -<p>なお、アンカンファレンスについては、1日目の終わりに<a href="https://fortee.jp/phperkaigi-2022/unconference/view/d332797a-8921-4706-a7e2-ee72640c9b5e">トークン問題の解説放送</a>もおこなった。</p> -<p>また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。 -今年は 3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。</p> -<h1 id="そして来年へ">そして来年へ……?</h1> -<p>PHPerKaigi 2023 があるかどうか存じ上げないが、あるとすれば、次の 4つを目標としたい。</p> -<ul> -<li>プロポーザルを出す</li> -<li>PHPer チャレンジのトークン問題を 5題作成する</li> -<li>現地に行く</li> -<li>PHPer チャレンジで圧勝する</li> -</ul> -<hr> -<p>最後になりましたが、PHPerKaigi のスタッフ、スポンサー、スピーカーのみなさん、素敵な時間をありがとうございました。</p> -<p>ではまた来年。</p> -]]></description> - </item> - - <item> - <title>PHPerKaigi 2022 トークン問題の解説</title> - <link>https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/</link> - <pubDate>Sat, 09 Apr 2022 21:50:19 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/</guid> - <description><![CDATA[ <h1 id="はじめに">はじめに</h1> -<p>本日開始された <a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> の PHPer チャレンジにおいて、弊社 <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> の問題を 3問作成した。この記事では、これらの問題の解説をおこなう。</p> -<p>リポジトリはこちら: <a href="https://github.com/nsfisis/PHPerKaigi2022-tokens">https://github.com/nsfisis/PHPerKaigi2022-tokens</a></p> -<h1 id="第1問-brainf_ckphp">第1問 brainf_ck.php</h1> -<p>ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">declare</span>(<span style="color:#a6e22e">strict_types</span><span style="color:#f92672">=</span><span style="color:#ae81ff">0</span><span style="color:#a6e22e">O1</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">namespace</span> <span style="color:#a6e22e">Dgcircus\PHPerKaigi\Y2022</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#e6db74">/** -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * @todo -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Run this program to acquire a PHPer token. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> */</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">https</span><span style="color:#f92672">://</span><span style="color:#a6e22e">creativecommons</span><span style="color:#f92672">.</span><span style="color:#a6e22e">org</span><span style="color:#f92672">/</span><span style="color:#a6e22e">publicdomain</span><span style="color:#f92672">/</span><span style="color:#a6e22e">zero</span><span style="color:#f92672">/</span><span style="color:#ae81ff">1.0</span><span style="color:#f92672">/</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">\error_reporting</span>(<span style="color:#f92672">~+!</span><span style="color:#e6db74">'We are hiring!'</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$z <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($f) <span style="color:#f92672">=></span> (<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=></span> $f(<span style="color:#a6e22e">fn</span>(<span style="color:#f92672">...</span>$xs) <span style="color:#f92672">=></span> $x($x)(<span style="color:#f92672">...</span>$xs)))(<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=></span> $f(<span style="color:#a6e22e">fn</span>(<span style="color:#f92672">...</span>$xs) <span style="color:#f92672">=></span> $x($x)(<span style="color:#f92672">...</span>$xs))); -</span></span><span style="display:flex;"><span>$id <span style="color:#f92672">=</span> <span style="color:#a6e22e">\spl_object_id</span>(<span style="color:#f92672">...</span>); -</span></span><span style="display:flex;"><span>$put <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($c) <span style="color:#f92672">=></span> <span style="color:#a6e22e">\printf</span>(<span style="color:#e6db74">'%c'</span>, $c); -</span></span><span style="display:flex;"><span>$mm <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($p, $n) <span style="color:#f92672">=></span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">\ArrayObject</span>(<span style="color:#a6e22e">\array_fill</span>(<span style="color:#f92672">+!!</span>[], $n, $p)); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$👉 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> [<span style="color:#f92672">++</span>$mp, <span style="color:#f92672">++</span>$pc]; -</span></span><span style="display:flex;"><span>$👈 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> [<span style="color:#f92672">--</span>$mp, <span style="color:#f92672">++</span>$pc]; -</span></span><span style="display:flex;"><span>$👍 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> [$mp, <span style="color:#f92672">++</span>$pc, <span style="color:#f92672">++</span>$m[$mp]]; -</span></span><span style="display:flex;"><span>$👎 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> [$mp, <span style="color:#f92672">++</span>$pc, <span style="color:#f92672">--</span>$m[$mp]]; -</span></span><span style="display:flex;"><span>$📝 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> [$mp, <span style="color:#f92672">++</span>$pc, $put($m[$mp])]; -</span></span><span style="display:flex;"><span>$🤡 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> <span style="color:#a6e22e">match</span> ($m[$mp]) { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">=></span> [$mp, $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=></span> <span style="color:#a6e22e">fn</span>($pc, $n) <span style="color:#f92672">=></span> <span style="color:#a6e22e">match</span> ($id($p[$pc])) { -</span></span><span style="display:flex;"><span> $b <span style="color:#f92672">=></span> $loop(<span style="color:#f92672">++</span>$pc, <span style="color:#f92672">++</span>$n), -</span></span><span style="display:flex;"><span> $e <span style="color:#f92672">=></span> $n <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">?</span> <span style="color:#f92672">++</span>$pc <span style="color:#f92672">:</span> $loop(<span style="color:#f92672">++</span>$pc, <span style="color:#f92672">--</span>$n), -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=></span> $loop(<span style="color:#f92672">++</span>$pc, $n), -</span></span><span style="display:flex;"><span> })($pc, <span style="color:#f92672">-!</span>[])], -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=></span> [$mp, <span style="color:#f92672">++</span>$pc], -</span></span><span style="display:flex;"><span>}; -</span></span><span style="display:flex;"><span>$🎪 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> <span style="color:#a6e22e">match</span> ($m[$mp]) { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">=></span> [$mp, <span style="color:#f92672">++</span>$pc], -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=></span> [$mp, $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=></span> <span style="color:#a6e22e">fn</span>($pc, $n) <span style="color:#f92672">=></span> <span style="color:#a6e22e">match</span> ($id($p[$pc])) { -</span></span><span style="display:flex;"><span> $e <span style="color:#f92672">=></span> $loop(<span style="color:#f92672">--</span>$pc, <span style="color:#f92672">++</span>$n), -</span></span><span style="display:flex;"><span> $b <span style="color:#f92672">=></span> $n <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">?</span> $pc<span style="color:#f92672">+!</span>[] <span style="color:#f92672">:</span> $loop(<span style="color:#f92672">--</span>$pc, <span style="color:#f92672">--</span>$n), -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=></span> $loop(<span style="color:#f92672">--</span>$pc, $n), -</span></span><span style="display:flex;"><span> })($pc, <span style="color:#f92672">-!</span>[])], -</span></span><span style="display:flex;"><span>}; -</span></span><span style="display:flex;"><span>$🐘 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($p) <span style="color:#f92672">=></span> $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=></span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">isset</span>($p[$pc]) <span style="color:#f92672">&&</span> $loop($m, $p, $b, $e, <span style="color:#f92672">...</span>($p[$pc]($m, $p, $b, $e, $mp, $pc))) -</span></span><span style="display:flex;"><span>)($mm(<span style="color:#f92672">+!!</span>[], <span style="color:#f92672">+</span>(<span style="color:#f92672">!</span>[]<span style="color:#f92672">.!</span>[])), $p, $id($🤡), $id($🎪), <span style="color:#f92672">+!!</span>[], <span style="color:#f92672">+!!</span>[]); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$🐘([ -</span></span><span style="display:flex;"><span> $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, -</span></span><span style="display:flex;"><span> $🤡, -</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, -</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, -</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, -</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, -</span></span><span style="display:flex;"><span> $👈, $👈, $👈, $👈, $👎, -</span></span><span style="display:flex;"><span> $🎪, -</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $📝, -</span></span><span style="display:flex;"><span> $👎, $👎, $📝, -</span></span><span style="display:flex;"><span> $👉, $👎, $👎, $👎, $📝, -</span></span><span style="display:flex;"><span> $👉, $👎, $👎, $👎, $📝, -</span></span><span style="display:flex;"><span> $👎, $👎, $📝, -</span></span><span style="display:flex;"><span> $👎, $📝, -</span></span><span style="display:flex;"><span> $👈, $📝, -</span></span><span style="display:flex;"><span> $👉, $👉, $👎, $👎, $📝, -</span></span><span style="display:flex;"><span> $👍, $👍, $👍, $👍, $👍, $👍, $👍, $📝, -</span></span><span style="display:flex;"><span> $👈, $👎, $👎, $👎, $👎, $📝, -</span></span><span style="display:flex;"><span> $👈, $📝, -</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $📝, -</span></span><span style="display:flex;"><span> $👉, $👎, $📝, -</span></span><span style="display:flex;"><span> $👈, $📝, -</span></span><span style="display:flex;"><span>]); -</span></span></code></pre></div><p>この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。</p> -<h2 id="解説">解説</h2> -<h3 id="絵文字">絵文字</h3> -<p>まず目につくのは大量の絵文字だろう。 -PHP は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。</p> -<h3 id="プログラム全体">プログラム全体</h3> -<p>Brainf*ck のインタプリタとプログラムになっている。 -Brainf*ck とは、難解プログラミング言語のひとつであり、ここで説明するよりも Wikipedia の該当ページを読んだ方がよい。</p> -<p><a href="https://ja.wikipedia.org/wiki/Brainfuck">https://ja.wikipedia.org/wiki/Brainfuck</a></p> -<p>なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。</p> -<pre tabindex="0"><code>+ + + + + + + + + + -[ - > + + + - > + + + + + - > + + + + + + + + + + + + - > + + + + + + + + + + - < < < < - -] -> + + + + + . -- - . -> - - - . -> - - - . -- - . -- . -< . -> > - - . -+ + + + + + + . -< - - - - . -< . -> + + . -> - . -< . -</code></pre><p>実行結果はこちら: <a href="https://ideone.com/22VWmb">https://ideone.com/22VWmb</a></p> -<p>それぞれの絵文字で表された関数が、各命令に対応している。</p> -<ul> -<li><code>$👉</code>: <code>></code></li> -<li><code>$👈</code>: <code><</code></li> -<li><code>$👍</code>: <code>+</code></li> -<li><code>$👎</code>: <code>-</code></li> -<li><code>$📝</code>: <code>.</code></li> -<li><code>$🤡</code>: <code>[</code></li> -<li><code>$🎪</code>: <code>]</code></li> -</ul> -<p><code>,</code> (入力) に対応する関数はない (このプログラムでは使わないので用意していない)。</p> -<p>なお、<code>$🐘</code> はいわゆる main 関数であり、プログラムの実行部分である。</p> -<h3 id="絵文字の選択">絵文字の選択</h3> -<p>おおよそ意味に合致するよう選んでいるが、<code>$🤡</code> と <code>$🎪</code> は弊社デジタルサーカスにちなんでいる。 -また、<code>$🐘</code> は PHP のマスコットの象に由来する。</p> -<h3 id="strict_types">strict_types</h3> -<p><code>declare</code> 文の <code>strict_types</code> に指定できるのは、<code>0</code> か <code>1</code> の数値リテラルだが、 -<code>0x0</code> や <code>0b1</code> のような値も受け付ける。 -今回は、PHP 8.1 から追加された、<code>0O</code> または <code>0o</code> から始まる八進数リテラルを使った。</p> -<h3 id="url">URL</h3> -<p>ソースコードのライセンスを示したこの部分だが、</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">https</span><span style="color:#f92672">://</span><span style="color:#a6e22e">creativecommons</span><span style="color:#f92672">.</span><span style="color:#a6e22e">org</span><span style="color:#f92672">/</span><span style="color:#a6e22e">publicdomain</span><span style="color:#f92672">/</span><span style="color:#a6e22e">zero</span><span style="color:#f92672">/</span><span style="color:#ae81ff">1.0</span><span style="color:#f92672">/</span> -</span></span></code></pre></div><p>完全に合法な PHP のコードである。 -<code>https:</code> 部分はラベル、<code>//</code> 以降は行コメントになっている。</p> -<h3 id="リテラルなしで数値を生成する">リテラルなしで数値を生成する</h3> -<p>ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。 -PHP では、型変換を利用することで任意の整数を作り出すことができる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[]); -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">1</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+!</span>[]); -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">2</span> <span style="color:#f92672">===</span> <span style="color:#f92672">!</span>[]<span style="color:#f92672">+!</span>[]); -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">3</span> <span style="color:#f92672">===</span> <span style="color:#f92672">!</span>[]<span style="color:#f92672">+!</span>[]<span style="color:#f92672">+!</span>[]); -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">10</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+</span>(<span style="color:#f92672">!</span>[]<span style="color:#f92672">.+!!</span>[])); -</span></span></code></pre></div><p><code>[]</code> に <code>!</code> を適用すると <code>true</code> が返ってくる。それに <code>+</code> -を適用すると、<code>bool</code> から <code>int</code> ヘの型変換が走り、<code>1</code> が生成される。<code>10</code> -はさらにトリッキーだ。まず <code>1</code> と <code>0</code> を作り、<code>.</code> で文字列として結合する -(<code>'10'</code>)。これに <code>+</code> を適用すると、<code>string</code> から <code>int</code> -への型変換が走り、<code>10</code> が生まれる (コード量に頓着しないなら、<code>1</code> を 10 -個足し合わせてももちろん 10 が作れる)。</p> -<p>また、<code>error_reporting</code> に指定しているのは <code>-1</code> である。 -これは、<code>!</code> によって文字列を <code>false</code> にし、<code>+</code> によって <code>false</code> を <code>0</code> にし、さらにビット反転して <code>-1</code> にしている。</p> -<h3 id="if-文なしで条件分岐"><code>if</code> 文なしで条件分岐</h3> -<p>三項演算子ないし <code>match</code> 式を使うことで、<code>if</code> を一切書かずに条件分岐ができる。 -また、<code>&&</code> / <code>||</code> も使えることがある。 -遅延評価が不要なケースでは、<code>[$t, $f][$cond]</code> のような形で分岐することもできる。</p> -<h3 id="whilefor-文なしでループ"><code>while</code>、<code>for</code> 文なしでループ</h3> -<p>不動点コンビネータを使って無名再帰する (詳しい説明は省略する。これらの単語で検索してほしい)。 -ここでは、一般に Z コンビネータとして知られるものを使った (<code>$z</code>)。</p> -<p>実際のところ、<code>$🤡</code> や <code>$🎪</code>、<code>$🐘</code> は、一度 Scheme (Lisp の一種) で書いてから PHP に翻訳する形で記述した。</p> -<p>なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) ので、 -あまりに長い brainf*ck プログラムを書くとスタックオーバーフローする。</p> -<h1 id="第2問-riddlephp">第2問 riddle.php</h1> -<p>ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#e6db74">/********************************************************* -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * This program displays a PHPer token. * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Guess 'N'. * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Hints: * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - N itself has no special meaning, e.g., 42, 8128, * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * it is selected at random. * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - Each element of $token represents a single letter. * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - One letter consists of 5x5 cells. * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - Remember, the output is a complete PHPer token. * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * License: * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * https://creativecommons.org/publicdomain/zero/1.0/ * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> *********************************************************/</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">N</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> <span style="color:#75715e">/* Change it to your answer. */</span>; -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672"><=</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&&</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672"><=</span> <span style="color:#ae81ff">0</span><span style="color:#a6e22e">b11111_11111_11111_11111_11111</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$token <span style="color:#f92672">=</span> [ -</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x14B499C</span>, -</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x0BE34CC</span>, <span style="color:#ae81ff">0x01C9C69</span>, -</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x0ECA069</span>, <span style="color:#ae81ff">0x01C2449</span>, <span style="color:#ae81ff">0x0FDB166</span>, <span style="color:#ae81ff">0x01C9C69</span>, -</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x01C1C66</span>, <span style="color:#ae81ff">0x0FC1C47</span>, <span style="color:#ae81ff">0x01C1C66</span>, -</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x10C5858</span>, <span style="color:#ae81ff">0x1E4E3B8</span>, <span style="color:#ae81ff">0x1A2F2F8</span>, -</span></span><span style="display:flex;"><span>]; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($token <span style="color:#66d9ef">as</span> $x) { -</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">'%025b'</span>, $x); -</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">'0'</span>, <span style="color:#e6db74">'1'</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">' '</span>, <span style="color:#e6db74">'#'</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x); -</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>)); -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">"</span><span style="color:#e6db74">{</span>$x<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n\n</span><span style="color:#e6db74">"</span>; -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。 -トークンを得るためには、ソースコードを読み、定数 <code>N</code> を特定する必要がある。</p> -<p>ここでは、私の想定解を解説する。</p> -<h2 id="読解">読解</h2> -<p>まずはソースコードを読んでいく。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$token <span style="color:#f92672">=</span> [ -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 略 -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>]; -</span></span></code></pre></div><p>数値からなる <code>$token</code> があり、各要素をループしている。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>; -</span></span></code></pre></div><p>まずは排他的論理和 (xor) を取り、</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">'%025b'</span>, $x); -</span></span></code></pre></div><p>二進数に変換して、</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">'0'</span>, <span style="color:#e6db74">'1'</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">' '</span>, <span style="color:#e6db74">'#'</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x); -</span></span></code></pre></div><p>0 を空白に、1 を <code>#</code> にし、</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>)); -</span></span></code></pre></div><p>5文字ごとに区切ったあと、改行で結合している。</p> -<h2 id="ヒント">ヒント</h2> -<p>次に、ソースコードに書いてあるヒントを読んでいく。</p> -<ul> -<li><code>N</code> それ自体は、42 や 8128 といったような特別な意味を持たず、ランダムに決められている</li> -<li><code>$token</code> の各要素は、1文字を表す</li> -<li>1文字は 5x5 のセルからなる</li> -<li>出力されるのは、完全な PHPer トークンである</li> -</ul> -<p>ここで、PHPer トークンは必ず <code>#</code> 記号から始まることを思いだすと、 -<code>$token</code> の最初の数字 <code>0x14B499C</code> は、変換の結果 <code>#</code> になるのではないかと予想される (なお、このことは、リポジトリの README ファイルに追加ヒントとして書かれている)。</p> -<h2 id="解く">解く</h2> -<p>ここまでわかれば、あと一歩で解ける。すなわち、<code>0x14B499C</code> が <code>#</code> に変換されるような <code>N</code> を見つければよい。</p> -<p><code>N</code> は高々</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672"><=</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&&</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672"><=</span> <span style="color:#ae81ff">0</span><span style="color:#a6e22e">b11111_11111_11111_11111_11111</span>); -</span></span></code></pre></div><p>なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0x14B499C</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">'%025b'</span>, $x); -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">'0'</span>, <span style="color:#e6db74">'1'</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">' '</span>, <span style="color:#e6db74">'#'</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x); -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>)); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>($x <span style="color:#f92672">===</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">" # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">" # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">" # # "</span>); -</span></span></code></pre></div><p>この一連の変換に対する逆変換を考えると、次のようになる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">" # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">" # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">" # # "</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">''</span>, <span style="color:#a6e22e">explode</span>(<span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>, $x)); -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">' '</span>, <span style="color:#e6db74">'#'</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">'0'</span>, <span style="color:#e6db74">'1'</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x); -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">bindec</span>($x); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$n <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#ae81ff">0x14B499C</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">"N = </span><span style="color:#e6db74">$n\n</span><span style="color:#e6db74">"</span>; -</span></span></code></pre></div><p>これを実行すると、<code>N</code> が得られる。</p> -<h1 id="第3問-toquinephp">第3問 toquine.php</h1> -<p>ソースコードはこちら。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">// License: https://creativecommons.org/publicdomain/zero/1.0/ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// This is a quine-like program to generate a PHPer token. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// Execute it like this: php toquine.php | php | php | php | ... -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> -</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#e6db74"><<<'</span><span style="color:#e6db74">Q</span><span style="color:#e6db74">' -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"><?cuc -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Yvprafr: uggcf://perngvirpbzzbaf.bet/choyvpqbznva/mreb/1.0/ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Guvf vf n dhvar-yvxr cebtenz gb trarengr n CUCre gbxra. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Rkrphgr vg yvxr guvf: cuc gbdhvar.cuc | cuc | cuc | cuc | ... -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%f$f = %f; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$f = fge_ebg13($f); $kf = [ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%f, -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">]; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$g = ahyy.snyfr; sbe ($v = 0; $v <= vagqvi(__YVAR__-035,6); ++$v) vs (!vffrg($kf[$v])) oernx; ryfr -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$g .= vzcybqr("\a", fge_fcyvg(fge_ercynpr(['0','1'], [' ','##'], fcevags(pue(37) . '025o', $kf[$v])), 012)) . "\a\a"; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$jf = neenl_znc(sa($j) => vzcybqr(', ', $j), neenl_puhax(neenl_znc(sa($k) => fcevags('0k' . pue(37) . '07K', $k), $kf), 10)); -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">cevags($f, $g, fge_ebg13("<<<'Q'\a{$f}\aQ"), vzcybqr(",\a", $jf)); -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span><span style="color:#e6db74">Q</span>; -</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_rot13</span>($s); $xs <span style="color:#f92672">=</span> [ -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x0AFABEA</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F2109F</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x0002800</span>, <span style="color:#ae81ff">0x1F2109F</span>, <span style="color:#ae81ff">0x0117041</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1F295B7</span>, -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x010FC21</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1151151</span>, <span style="color:#ae81ff">0x010FC21</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F295B7</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F295B7</span>, <span style="color:#ae81ff">0x1F8C63F</span>, -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x1F8C631</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x17AD6BD</span>, <span style="color:#ae81ff">0x17AD6BD</span>, <span style="color:#ae81ff">0x1F8C63F</span>, <span style="color:#ae81ff">0x1F295B7</span>, -</span></span><span style="display:flex;"><span>]; -</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">.</span><span style="color:#66d9ef">false</span>; <span style="color:#66d9ef">for</span> ($i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; $i <span style="color:#f92672"><=</span> <span style="color:#a6e22e">intdiv</span>(<span style="color:#66d9ef">__LINE__</span><span style="color:#f92672">-</span><span style="color:#ae81ff">035</span>,<span style="color:#ae81ff">6</span>); <span style="color:#f92672">++</span>$i) <span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">isset</span>($xs[$i])) <span style="color:#66d9ef">break</span>; <span style="color:#66d9ef">else</span> -</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">.=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>, <span style="color:#a6e22e">str_split</span>(<span style="color:#a6e22e">str_replace</span>([<span style="color:#e6db74">'0'</span>,<span style="color:#e6db74">'1'</span>], [<span style="color:#e6db74">' '</span>,<span style="color:#e6db74">'##'</span>], <span style="color:#a6e22e">sprintf</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#ae81ff">37</span>) <span style="color:#f92672">.</span> <span style="color:#e6db74">'025b'</span>, $xs[$i])), <span style="color:#ae81ff">012</span>)) <span style="color:#f92672">.</span> <span style="color:#e6db74">"</span><span style="color:#ae81ff">\n\n</span><span style="color:#e6db74">"</span>; -</span></span><span style="display:flex;"><span>$ws <span style="color:#f92672">=</span> <span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">fn</span>($w) <span style="color:#f92672">=></span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">', '</span>, $w), <span style="color:#a6e22e">array_chunk</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=></span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">'0x'</span> <span style="color:#f92672">.</span> <span style="color:#a6e22e">chr</span>(<span style="color:#ae81ff">37</span>) <span style="color:#f92672">.</span> <span style="color:#e6db74">'07X'</span>, $x), $xs), <span style="color:#ae81ff">10</span>)); -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">printf</span>($s, $t, <span style="color:#a6e22e">str_rot13</span>(<span style="color:#e6db74">"<<<'D'</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">{</span>$s<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">D"</span>), <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">",</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>, $ws)); -</span></span></code></pre></div><p>コメントにもあるとおり、次のようにして実行すれば答えがでてくる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php toquine.php | php | php | php | ... -</span></span></code></pre></div><p>実際にはもう少しパイプで繋げなければならない。</p> -<h2 id="解説-1">解説</h2> -<h3 id="プログラム全体-1">プログラム全体</h3> -<p>コメントにもあるとおり、これは quine (風) のプログラムになっている。 -Quine とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。</p> -<p>このプログラムは、実行すると自身とほとんど同じプログラムを出力する。 -異なるのはトークンになっている部分のみである。</p> -<h3 id="トークン">トークン</h3> -<p><code>$xs</code> がトークンに対応している。変換のロジックは <code>riddle.php</code> とほぼ同じなので省略する。</p> -<h3 id="状態保持">状態保持</h3> -<p>トークンの何文字目まで出力したかを、ソースコードを変えずに (quine なので) 覚えておく必要がある。 -このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、<code>__LINE__</code> から情報を取得している。</p> -<h3 id="rot-13">ROT 13</h3> -<p>Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。 -これがあまり美しくないので、<code>toquine.php</code> では、ROT 13 変換を使って難読化した。</p> -<p>それにしてもなぜこんなものが標準ライブラリに……。</p> -<h1 id="おわりに">おわりに</h1> -<p>解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。</p> -<p>今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、 -来年は 5問、より面白い問題を持っていきます。</p> -<p>実はもう作りはじめているので、どうか来年もありますように……。</p> -]]></description> - </item> - - <item> - <title>PHPerKaigi 2021</title> - <link>https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/</link> - <pubDate>Tue, 30 Mar 2021 23:22:40 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/</guid> - <description><![CDATA[ <h1 id="phperkaigi-2021-参加レポ">PHPerKaigi 2021 参加レポ</h1> -<p>2021-03-26 から 2021-03-28 にかけて開催された、<a href="https://phperkaigi.jp/2021/">PHPerKaigi 2021</a> に一般参加者として参加した。 -弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> (今年1月から勤務) はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p> -<p>このようなカンファレンスには初めて参加するのでかねてより心待ちにしていたのだが、生憎2日目から体調を崩してしまい、この記事も途中までとなっている。まだ見ていないセッションも多いが、ひとまず現時点での参加レポを書いておく。</p> -<p>発表はトラック A、B に分かれていたのだが、今回はすべて A トラックを視聴している (切り替えるのが面倒だっただけ)。</p> -<h2 id="凡例">凡例</h2> -<blockquote> -<p>発表・スライドのメモ (引用ではない)</p> -</blockquote> -<p>感想など</p> -<h2 id="day-0-前夜祭-20210327">Day 0 前夜祭 (2021/03/27)</h2> -<h3 id="1730-a">17:30 [A]</h3> -<p>PHP で AWS Lambda</p> -<blockquote> -<p>Rails のプロジェクトを PHPer のメンバのみでメンテ -→他のメンバもわかる PHP にリプレースを検討</p> -<p>サーバレス</p> -<ul> -<li>サーバ・インフラの管理が不要</li> -<li>アプリケーションコードの知識だけで保守可能</li> -</ul> -<p>ゼロベースで作れる案件が (Railsの件とは別に) あるため、そちらで試験的に導入?</p> -<p>AWSの学習 -AWS のドキュメント -DevelopersIO</p> -<p>AWS Lambda のカスタムランタイムで PHP を動かす</p> -<p>サーバのセットアップや維持管理を気にしなくて良い -サーバーレスで PHP を動かすツールがすでにある -サーバーレス構築はすんなり</p> -<p>今は Laravel がルーティングしている -Laravel Livewire を Lambda に載せられないか? -デプロイ方法は? -バッチ処理は? (Lambda は 15分の制限)</p> -<p>Lambda でコンテナイメージがサポートされるように</p> -<p>抽象化されたもの「だけ」しか知らないよりも具象の理解は助けになる</p> -</blockquote> -<p>AWS Lambda のような Function as a Service はマイクロサービス化における一つの到達点に思えるのだが、これを使って実際に web サービスを作る具体的なイメージがまだ見えない (注: すべて for me として書いている)。</p> -<p>PHP on AWS Lambda があれだけ簡単に動かせるのには驚いた。</p> -<p>勝手に AWS Lambda だとフットプリントの軽さが求められそう (= PHP + Laravel などでは動かなさそう) だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。</p> -<h3 id="1810-a">18:10 [A]</h3> -<p>大規模サイトの SEO</p> -<blockquote> -<p>大規模サイト (100万ページ以上) -Google の基準</p> -<p>クロールバジェットを意識したSEO</p> -<p>大規模サイトでコンテンツが中頻度 (1回/週) で更新 OR 中規模サイト (10,000以上) でコンテンツが目まぐるしく変更される -これを満たさないなら、クロールバジェットを考えなくてもいい</p> -<p>サーチコンソール -「カバレッジ」の「除外」 -多すぎるのは問題→クロールバジェットを浪費している</p> -<ul> -<li>クエリの順番を決める</li> -<li>空の値のルールを決めておく</li> -<li>リダイレクトすればインデックスはうまくいく</li> -<li>リンクが存在する限りクロールはされる</li> -</ul> -<p>リニューアル前のURL</p> -<p>インデックスは移行される -リンクのURLが存在する限り、別のURLとしてクロールされる -リダイレクトされるとはいえ、リニューアル前のURLは移行した方が良い -リニューアルで無視されるようになったパラメータも注意</p> -<p>robotes.txt で拒否しているのにクロールされる -一時的に拒否を外して 404 や 301 を読ませる -内部リンクを確認する -JS でのリンクに書き換え</p> -<p>クエリパラメータからURLのパスに -<code>/tokyo?area=HOGE</code> → <code>/tokyo/HOGE</code></p> -<p>URL 設計だいじ</p> -</blockquote> -<p>SEO (Search Engine Optimization) は大して知らないので新鮮な話が多かった。その分語れることも少ない……。</p> -<h3 id="1850-a">18:50 [A]</h3> -<blockquote> -<p>知覚可能 -操作可能 -理解可能 -堅牢 ちゃんとしたHTMLを書く (閉じタグ・入れ子構造など)</p> -<ul> -<li> -<p>標準の HTML を適切に使う</p> -</li> -<li> -<p>WAI-ARIA</p> -</li> -<li> -<p>キーボードフレンドリー</p> -</li> -<li> -<p>マシンフレンドリー</p> -</li> -<li> -<p>SEOフレンドリー</p> -</li> -</ul> -<p>button タグ -→キーボード -h1 タグ -→スクリーンリーダー・クローラ -a タグ</p> -<p>WAI-ARIA -HTML では表現できないセマンティクスを追加する</p> -<ul> -<li>ロール -<ul> -<li>何をするのか?</li> -<li>ユーザーアクションによって変化しない</li> -</ul> -</li> -<li>プロパティ -<ul> -<li>関連づけられたデータ</li> -</ul> -</li> -<li>ステート -<ul> -<li>現在の状態</li> -</ul> -</li> -</ul> -<p>まずは標準の HTML 要素で解決する -何でもかんでも WAI-ARIA を使えばいいというものではない</p> -<p>マウスホバーでツールチップが出てくるが、キーボード操作では出てこない</p> -<p>VoiceOver</p> -<p>全ての属性を使う必要はない -あくまでアクセシビリティを上げるための方法の一つにすぎない</p> -</blockquote> -<p>つい最近 WAI-ARIA についての記事を読んだばかりだったので個人的にタイムリーな話題だった。(あまりこの言葉を使いたくないのだが) いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。</p> -<h3 id="1930-a">19:30 [A]</h3> -<p>PHP で FUSE</p> -<p>個人的に楽しみだった発表。</p> -<blockquote> -<p>VFS (virtual filesystem) vs 具体的なファイルシステム</p> -<p>最適な実装方法は状況により異なる</p> -<p>アプリケーションに見せるAPIは変えずに実装を隠蔽する→VFS</p> -<p>カーネルのプログラムを作るのは難しい</p> -<ul> -<li>権限がデカすぎる</li> -<li>システム全体がクラッシュ</li> -<li>セキュリティリスク</li> -<li>開発サイクルを回しづらい</li> -<li>ネイティブコードにコンパイルされる言語である必要がある</li> -</ul> -<p>Filesystem in USEr space (FUSE)</p> -<ul> -<li>特定の C の関数を呼ぶことで filesystem が作れる</li> -<li>FFI を持つ言語なら FUSE が使える</li> -</ul> -<p>SSHFS / s3fs / Docker Desktop</p> -<p>Linux 以外でも使える</p> -<ul> -<li>dokany (on Windows)</li> -<li>osxfuse</li> -</ul> -<p>VFS: システムコールが呼ばれると、ファイルシステムによってコール -FUSE: カーネル空間からユーザ空間へ通信</p> -<p>高レベルなラッパで型をつける</p> -<p>PHP 以外では Wordpress を FUSE にマウントする実装がある (C, Python など)</p> -<ul> -<li>grep できる</li> -<li>sed できる</li> -<li>編集できる</li> -</ul> -</blockquote> -<p>期待通りの興味深い発表だった。FUSE 自体も今回の発表で知ったのだが、これ本体の実装を見るのも面白そうだ。 -この発表を聞きながらファイルシステムにマウントできそうなものを考えていたのだが、およそ木構造をしているものすべてと言えそうだ (ハンマーしか持っていないと云々)。何かできそうだがなかなか思いつかない。</p> -<h2 id="day-1-20210327">Day 1 (2021/03/27)</h2> -<h3 id="1050-a">10:50 [A]</h3> -<p>ATDD</p> -<blockquote> -<ul> -<li>ユーザーストーリー</li> -<li>ユニットテスト</li> -<li>CI/CD</li> -</ul> -<p>ユーザストーリーの受け入れ条件が曖昧になりがち -デグレチェックがユニットレベルでは収まらない場合、手動で同じシナリオをテストしている</p> -<p>Q2の強化 -アジャイルテストの4象限</p> -<p>技術面/ビジネス面 -開発チーム支援(コーディング前・コーディング中)/製品批評(コーディング後)</p> -<ul> -<li>Q1: 技術面 & チーム支援 -<ul> -<li>TDD</li> -<li>ユニットテストなど</li> -</ul> -</li> -<li>Q2: ビジネス面 & チーム支援 -<ul> -<li>ATDD</li> -<li>ビジネス面の受け入れテストで駆動する</li> -</ul> -</li> -</ul> -<p>Agile Alliance -ユーザストーリーのスキルレベルを高める</p> -<p>テストピラミッド</p> -<ul> -<li> -<p>UI Tests</p> -</li> -<li> -<p>Service Tests</p> -</li> -<li> -<p>Unit Tests</p> -</li> -<li> -<p>異なる粒度のテストを書く</p> -</li> -<li> -<p>高レベルになるほど、持つべきテストは少なくなる</p> -<ul> -<li>ピラミッド型になる</li> -</ul> -</li> -</ul> -<p>高レベルテストが多すぎる→アイスクリームコーン アンチパターン</p> -<p>ATDD (Acceptance TDD) -API経由・UI経由での高レベルテスト E2E test</p> -<p>ストーリ受け入れテスト</p> -<p>入れ子のフィードバックループ -ATDD(外側) と TDD(内側)</p> -<p>外部品質・内部品質</p> -<p>バーティカルスライスのデリバリー</p> -<ul> -<li>cucumber</li> -<li>gauge</li> -<li>behat</li> -</ul> -<p>ユビキタス言語 -手動テストもspecに書く -自動化は可能だがコスパが悪い -失敗することがわかっているテスト(レッドテスト)はCIから外す -失敗時の原因究明が難しい -饒舌なエラーメッセージ -状況のスナップショット</p> -<p>Continuous Testing</p> -</blockquote> -<p>User Acceptance Test (UAT) くらいの規模になると個人開発・趣味開発では触れない領域なので、大いに勉強になった。スライドに添付されている資料が相当に充実していたので、これを読むのが本番といった様相すら感じる。 -高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。</p> -<h3 id="1150-a">11:50 [A]</h3> -<p>型解析を用いたリファクタリング</p> -<p>型のある世界で生きてきた身として大いに楽しみにしていた発表。</p> -<blockquote> -<ul> -<li>PHPStan</li> -<li>Phan</li> -<li>Psalm</li> -</ul> -<p>autoload も認識できる -bootstrapFiles</p> -<p>編集箇所と利用箇所を CI でチェック -ルールレベルを徐々に引き上げていく -警告が多すぎると見落としてしまう・無視されやすくなる</p> -<p>型がついていないことによるエラーが多い</p> -<p>型よりも詳細な検査 <code>Util_Assert::min</code></p> -<p>SQL を静的解析 -placeholder の型付け</p> -<p>警告レベルを低いレベルから導入 -タイプヒントを積極的に書いていく -PHPStan の拡張を追加する</p> -</blockquote> -<p>昨今、動的型付き言語での型宣言・型アノテーション・型ヒントの導入が相次いでいる。長らく静的型付き言語を書いてきた私からすると、ようやく気づいたかといったところだが、ともかく型を導入する言語が増えてきた。 -今のプロジェクトでも新しく追加するコードには型をつけるよう努めているが、どうしても古いコードには型がついていない。個人的には型のないコードに対してどう型を自動的に付けるかという点に興味があり、その点で Ruby の typeprof には注目している。</p> -<h3 id="1230-a">12:30 [A]</h3> -<p>昼食をとっていた。事前に何か食料を買っておくべきだった。</p> -<h3 id="1310-a">13:10 [A]</h3> -<p>Documentation as Code</p> -<p>この発表も以前から非常に楽しみにしていた。</p> -<blockquote> -<p>開発開始までのオーバーヘッド -新規にチームにジョイン -担当範囲外の機能を理解 -オンボーディングのコスト</p> -<p>PHPerKaigi 2020 で発表あり</p> -<p>継続的にシステムの理解を助けるドキュメント</p> -<p>継続的ドキュメンテーション -システムとドキュメントの乖離</p> -<p>書いてあることが間違っている・足りない</p> -<ul> -<li>徐々にずれていく</li> -<li>システムの更新タイミングとドキュメントの更新タイミングに差がある</li> -</ul> -<p>システムとドキュメントは対応関係がある</p> -<ul> -<li>間違ったドキュメント</li> -<li>存在しないドキュメント</li> -</ul> -<p>システムとドキュメントの乖離を定量化する -継続的に -システムの更新に近いタイミングで ドキュメントを更新し続ける</p> -<p>Documentation as Code</p> -<p>コードと同じツールでドキュメントを書く</p> -<ul> -<li>issue tracker</li> -<li>vcs</li> -<li>plain text markup</li> -<li>automation</li> -</ul> -<p>開発者 -システム -ドキュメント -構造化データ -ソフトウェア</p> -<p>システムから構造化データを抽出する -PHPDoc -OpenAPI</p> -<p>ビュー 関心ごとに合わせてアーキテクチャを一つ以上の側面(断面)で説明する</p> -<p>ビューの単位でドキュメントに</p> -<p>スタックトレースからのドキュメント生成</p> -</blockquote> -<p>ドキュメントの管理は現プロジェクトでも課題と感じている。作られた当初は正しくても、実態と乖離していくのを止めるのは困難を極める。全体的に興味深い発表だったが、特にスタックトレースからのドキュメント生成というアイデアに惹かれるものを感じた。スタックトレースという実態と不可分な (乖離しない) 情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。</p> -<h3 id="1410-a">14:10 [A]</h3> -<p>cookie による session 管理</p> -<p>全体的に基本的な話だったので特に触れない。Cookie やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。</p> -<h3 id="1450-a">14:50 [A]</h3> -<p>PHP のエラーと例外</p> -<blockquote> -<p>エラー PHPエンジンがエラーを通知する -例外 プログラムが投げる</p> -<p>PHP7-8とエラー</p> -<p>PHPエンジンのエラーの一部が \Error に変換されるようになった -→ try-catch で捕捉できる</p> -<p>\Error は例外とは異なる</p> -<p>PHP8 でエラーレベルの引き上げ</p> -<ul> -<li>捕捉すべきもの -<ul> -<li>recoverable</li> -</ul> -</li> -<li>捕捉すべきでないもの -<ul> -<li>unrecoverable</li> -<li>開発時に対処できるもの</li> -</ul> -</li> -</ul> -<p>例外</p> -<ul> -<li>捕捉して事後処理</li> -<li>捕捉せず(or 捕捉した上で)さらに上に是非を問う</li> -</ul> -<p>開発段階で例外を把握し、ハンドリングを考えておく</p> -<p>\Throwable \Exception と \Error</p> -<p>\Error はキャッチすべきでない</p> -<ul> -<li> -<p>\Error</p> -<ul> -<li>本番で起きてはいけない</li> -</ul> -</li> -<li> -<p>\LogicException</p> -<ul> -<li>本番で起きてはいけない -→生じないのだから捕捉もしない</li> -</ul> -</li> -<li> -<p>\RuntimeException</p> -<ul> -<li>起こるかもしれないので本番環境でも考慮する</li> -</ul> -</li> -</ul> -<p>捕捉して対応するのではなく、未然に防ぐ</p> -<p>独自例外を使う -\Exception を投げてしまうと、 -catch (\Exception)せざるを得ない -→catch 範囲が広すぎる</p> -<p>SPL の例外を使う</p> -<p>例外翻訳 -上位のレイヤが下位のレイヤの例外を捕捉し、上位レイヤのAPIに「翻訳」する -下位レイヤの知識に依存させない</p> -<p>@throws -捕捉してほしい例外を書き連ねておく</p> -<p>呼び出しもとに負わせたい責任</p> -</blockquote> -<p>PHP を学んでいる途中の私としては、今まさに聞きたい発表だった (現時点で PHP を書き始めてから 4ヶ月ほどになる)。</p> -<p>個人的に例外やエラーを最もうまく扱っているのは Go、Swift、Rust、Haskell などのエラーを「値として」扱う言語だと思っている。try-catch は通常の処理フローを完全に壊してしまう上、構文としても重すぎる。値としてのエラー通知は C言語時代への回帰ともいえるが、その頃と異なるのはエラーを暗黙のうちに握り潰すことがないということだ。これらの言語は型を持っており、静的に検証ができる (C のそれはまともな型付けではない。念のため)。</p> -<p>PHP のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。</p> -<h3 id="1530-a">15:30 [A]</h3> -<p>Laravel のメール認証</p> -<p>Laravel の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。</p> -<h3 id="1610-a">16:10 [A]</h3> -<p>gRPC</p> -<blockquote> -<p>Unary RPCs -Server streaming RPCs -Client streaming RPCs -Bidirectional streaming RPCs</p> -<p>Protobuf</p> -<p>実装とAPIが乖離しにくい -自動生成 -複数言語でも相互に使える</p> -<p>マイクロサービスのサービス通信 -スマホアプリ -ゲームサーバ</p> -<p>PHP では?</p> -<p>PHP ではストリーミングが難しい -リクエストごとにプロセスが使い捨て</p> -<p>PHP ではgRPCのクライアントしか対応していない</p> -<p>gRPC-Web -ブラウザで扱うためのJSライブラリ+プロトコル</p> -<p>HTTP/1.1 でも使える -Unary RPC と Server streaming RPC のみ</p> -<p>Envoy -Nginx などで相互に gRPC と gRPC-Web で変換</p> -<p>Amp -イベント駆動な並行処理のフレームワーク</p> -<p>HTTP/2 対応</p> -<p>C#のgRPC-Webが楽</p> -</blockquote> -<p>(発表の中でもまさに同じことをおっしゃっていたが) PHP 以外の方が向いているだろう、というのが第一の感想である。gRPC はそれ自体というよりも Protobuf というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。</p> -<h3 id="1650-a">16:50 [A]</h3> -<p>アーキテクチャテスト</p> -<blockquote> -<p>Independent Core Layer Pattern</p> -<p>開発初期のアーキテクチャが崩れる -アーキテクチャ観点のコードレビューができない</p> -<p>どこにクラスを置けばよいか? -ドキュメントがない</p> -<p>アーキテクチャ設計に関する知識が属人化・暗黙知化</p> -<p>ガイドライン</p> -<ul> -<li>最初にルールを決めるのは簡単</li> -<li>ルール通り作り始めるのも簡単 -<ul> -<li>→維持するのが難しい、人が決めたものゆえ壊れやすい</li> -</ul> -</li> -</ul> -<p>PHP の特性</p> -<ul> -<li>クラスは public</li> -<li>可視性の制御が public / protected / private のみ</li> -<li>依存関係の制御が困難</li> -</ul> -<p>アーキテクチャテスト -クラスの依存関係や実装ルールをコードとして表現し、自動テスト化する</p> -<ul> -<li>deptrac</li> -<li>phpat</li> -</ul> -<p>Independent Core Layer Pattern</p> -<p>アーキテクチャテストの失敗</p> -<ul> -<li>実装誤り</li> -<li>or アーキテクチャが適切でない -<ul> -<li>開発の過程でフィードバックしていく</li> -</ul> -</li> -</ul> -<p>モジュラーモノリス→マイクロサービスへ</p> -</blockquote> -<h2 id="day-2-20210328">Day 2 (2021/03/28)</h2> -<p>冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。</p> -<p>残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。</p> -<h2 id="全体の感想">全体の感想</h2> -<p>Day 2 にほとんど参加できなかったのは残念だが、イベント自体は大変楽しく、また興味深いものであった。自分がまったく知らない領域の話を聞けるのはこうしたイベントならではだと感じる。オンライン開催ゆえ現地に行く必要がなく、気軽に参加できたのも (特に初参加者として) 嬉しいポイントだった。</p> -<p>今回、雑談/登壇者への質問等向けに Discord サーバもあったのだが、こちらは参加こそしたものの ROM のままになってしまった。発表に1ウィンドウ、メモを書くのに1ウィンドウ、Discord 表示に 1ウィンドウで私にはもう脳のリソースとディスプレイのスペースが追いつかなかった (さらにいうと Zoom でアンカンファレンスもやっていたようだ。こちらはまったく参加していない)。</p> -<p>1つ個人的な反省点としては、一つ一つのセッションを真剣に聞き過ぎたというものがある。もっと適当に聞いておけばよかった。これだけだと大変語弊があるのだが、言い方を変えると、Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。 -まあ初カンファレンスだし、とお茶を濁しておこう。</p> -<p>さて、カンファレンスで一つ気になったことがある。それは、Discord という書き込み場所が増えたことでニコ生のコメントの流量が吸い取られてしまったのではないか、という点だ。ニコニコだけ見ていると過疎っているかのように見えた発表も、Discord の方では盛り上がっている、というのを何度か見かけた。ニコニコのコメント方式は盛り上がりを如実に反映するが、逆もまたしかり。Discord があったこと自体はプラスだったと思うが、この点はマイナスだったのではないかと感じる。</p> -<hr> -<p>最後になりましたが、毎年の PHPerKaigi 開催にご尽力されている皆様、スピーカーの皆様、楽しい3日間でした。ありがとうございました! -(ずっと常体で書いてしまったのでいきなり仏頂面から笑顔になったようで気持ち悪い)</p> -<p>ではまた来年。</p> -]]></description> - </item> - - </channel> -</rss> diff --git a/docs/tags/conference/index.html b/docs/tags/conference/index.html deleted file mode 100644 index 40c8675..0000000 --- a/docs/tags/conference/index.html +++ /dev/null @@ -1,92 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - - <title>conference | REPL: Rest-Eat-Program Loop</title> - - <meta name="description" content=""> - <meta name="author" content="nsfisis"> - - <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet"> - - <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg"> - <meta name="generator" content="Hugo 0.102.1" /> - - <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/conference/feed.xml" title="REPL: Rest-Eat-Program Loop" /> - - </head> - <body class="list"> - <header class="header"> - <nav class="nav"> - <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p> - </nav> - </header> - <main class="main"> - -<header class="page-header"><h1>conference</h1></header> - -<article class="post-entry"> - <header class="entry-header"> - <h2>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</h2> - </header> - <section class="entry-content"> - <p>PHP カンファレンス沖縄の懇親会 LT で出題されたコードゴルフの問題を解いてみた。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2022-08-27</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/"></a> -</article> -<article class="post-entry"> - <header class="entry-header"> - <h2>PHPerKaigi 2022</h2> - </header> - <section class="entry-content"> - <p>2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に参加した。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2022-05-01</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/"></a> -</article> -<article class="post-entry"> - <header class="entry-header"> - <h2>PHPerKaigi 2022 トークン問題の解説</h2> - </header> - <section class="entry-content"> - <p>PHPerKaigi 2022 で私が作成した PHPer チャレンジ問題を解説する。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2022-04-09</time>, updated on <time>2022-04-16</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/"></a> -</article> -<article class="post-entry"> - <header class="entry-header"> - <h2>PHPerKaigi 2021</h2> - </header> - <section class="entry-content"> - <p>2021-03-26 から 2021-03-28 にかけて開催された、PHPerKaigi 2021 に参加した。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2021-03-30</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/"></a> -</article></main> -<footer class="footer"> - <span>© 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span> - <span>·</span> - <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span> -</footer> -<script src="https://blog.nsfisis.dev/highlight.min.js"></script> -<script> - hljs.initHighlightingOnLoad(); -</script> -</body> -</html> - diff --git a/docs/tags/conference/page/1/index.html b/docs/tags/conference/page/1/index.html deleted file mode 100644 index 740f29e..0000000 --- a/docs/tags/conference/page/1/index.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <title>https://blog.nsfisis.dev/tags/conference/</title> - <link rel="canonical" href="https://blog.nsfisis.dev/tags/conference/"> - <meta name="robots" content="noindex"> - <meta charset="utf-8"> - <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/conference/"> - </head> -</html> diff --git a/docs/tags/cpp/feed.xml b/docs/tags/cpp/feed.xml deleted file mode 100644 index 435e2f9..0000000 --- a/docs/tags/cpp/feed.xml +++ /dev/null @@ -1,89 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> - <channel> - <title>cpp on REPL: Rest-Eat-Program Loop</title> - <link>https://blog.nsfisis.dev/tags/cpp/</link> - <description>Recent content in cpp on REPL: Rest-Eat-Program Loop</description> - <generator>Hugo -- gohugo.io</generator> - <language>ja-JP</language> - <lastBuildDate>Sat, 02 Oct 2021 09:38:30 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/cpp/feed.xml" rel="self" type="application/rss+xml" /> - <item> - <title>[C++] 属性構文の属性名にはキーワードが使える [[void]] [[for]]</title> - <link>https://blog.nsfisis.dev/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/</link> - <pubDate>Sat, 02 Oct 2021 09:38:30 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/</guid> - <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。 -元 URL: <a href="https://qiita.com/nsfisis/items/94090937bcf860cfa93b">https://qiita.com/nsfisis/items/94090937bcf860cfa93b</a></p> -<hr> -<p>タイトル落ち。まずはこのコードを見て欲しい。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e"><iostream></span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[alignas]] [[alignof]] [[and]] [[and_eq]] [[asm]] [[auto]] [[bitand]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[bitor]] [[bool]] [[break]] [[case]] [[catch]] [[char]] [[char16_t]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[char32_t]] [[class]] [[compl]] [[const]] [[const_cast]] [[constexpr]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[continue]] [[decltype]] [[default]] [[delete]] [[do]] [[double]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[dynamic_cast]] [[else]] [[enum]] [[explicit]] [[export]] [[extern]] [[false]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[final]] [[float]] [[for]] [[friend]] [[goto]] [[if]] [[inline]] [[int]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[long]] [[mutable]] [[namespace]] [[new]] [[noexcept]] [[not]] [[not_eq]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[nullptr]] [[operator]] [[or]] [[or_eq]] [[override]] [[private]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[protected]] [[public]] [[register]] [[reinterpret_cast]] [[return]] [[short]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[signed]] [[sizeof]] [[static]] [[static_assert]] [[static_cast]] [[struct]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[switch]] [[template]] [[this]] [[thread_local]] [[throw]] [[true]] [[try]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[typedef]] [[typeid]] [[typename]] [[union]] [[unsigned]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[virtual]] [[void]] [[volatile]] [[wchar_t]] [[while]] [[xor]] [[xor_eq]]</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">// [[using]] -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">int</span> main() { -</span></span><span style="display:flex;"><span> std<span style="color:#f92672">::</span>cout <span style="color:#f92672"><<</span> <span style="color:#e6db74">"Hello, World!"</span> <span style="color:#f92672"><<</span> std<span style="color:#f92672">::</span>endl; -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><blockquote> -<p>コンパイラのバージョン -$ clang++ –version -Apple clang version 11.0.0 (clang-1100.0.33.8) -Target: x86_64-apple-darwin19.6.0 -Thread model: posix -InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin</p> -<p>コンパイルコマンド (C++17指定) -$ clang++ –std=c++17 hoge.cpp</p> -</blockquote> -<p>この記事から得られるものはこれ以上ないので以下は蛇足になる。</p> -<p>別件で cppreference.com の <a href="https://en.cppreference.com/w/cpp/language/identifiers">identifier のページ</a> を読んでいた時、次の文が目に止まった。</p> -<blockquote> -<ul> -<li>the identifiers that are keywords cannot be used for other purposes; -<ul> -<li>The only place they can be used as non-keywords is in an attribute-token. (e.g. [[private]] is a valid attribute) (since C++11)</li> -</ul> -</li> -</ul> -</blockquote> -<p>キーワードでも属性として指定する場合は非キーワードとして使えるらしい。 -実際にやってみる。</p> -<p>同サイトの [keywords のページ] (<a href="https://en.cppreference.com/w/cpp/keyword">https://en.cppreference.com/w/cpp/keyword</a>) から一覧を拝借し、上のコードが出来上がった (C++17 においてキーワードでないものなど、一部省いている)。 -大量の警告 (unknown attribute ‘〇〇’ ignored) がコンパイラから出力されるが、コンパイルできる。</p> -<p>上のコードでは <code>[[using]]</code> をコメントアウトしているが、これは <code>using</code> キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#75715e">// using の例 -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">[[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]]</span> <span style="color:#960050;background-color:#1e0010">の糖衣構文</span> -</span></span></code></pre></div><p>C++17 の仕様も見てみる (正確には標準化前のドラフト)。</p> -<p>引用元: <a href="https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4">https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4</a></p> -<blockquote> -<p>If a keyword or an alternative token that satisfies the syntactic requirements of an identifier is contained in an attribute-token, it is considered an identifier.</p> -</blockquote> -<p>「<code>identifier</code> の構文上の要件を満たすキーワードまたは代替トークンが <code>attribute-token</code> に含まれている場合、<code>identifier</code> とみなされる」とある。どうやら間違いないようだ。</p> -<p>ところで、代替トークン (alternative token) とは <code>and</code> (<code>&</code>) や <code>bitor</code> (<code>|</code>) などのことだが、<code>identifier</code> の構文上の要件を満たさないような代替トークンなどあるのか? -疑問に思って調べたところ、代替トークンという語にはダイグラフも含まれるらしい (参考: <a href="https://timsong-cpp.github.io/cppwp/n4659/lex.digraph">同ドラフト</a>)</p> -<ul> -<li><code><%</code> → <code>{</code></li> -<li><code>%></code> → <code>}</code></li> -<li><code><:</code> → <code>[</code></li> -<li><code>:></code> → <code>]</code></li> -<li><code>%:</code> → <code>#</code></li> -<li><code>%:%:</code> → <code>##</code></li> -</ul> -<p>「<code>identifier</code> の構文上の要件を満たさないような代替トークン」はこれらが当てはまると思われる。</p> -<p>調べた感想: 字句解析器か構文解析器が辛そう</p> -]]></description> - </item> - - </channel> -</rss> diff --git a/docs/tags/cpp/index.html b/docs/tags/cpp/index.html deleted file mode 100644 index 73b29b1..0000000 --- a/docs/tags/cpp/index.html +++ /dev/null @@ -1,56 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - - <title>cpp | REPL: Rest-Eat-Program Loop</title> - - <meta name="description" content=""> - <meta name="author" content="nsfisis"> - - <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet"> - - <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg"> - <meta name="generator" content="Hugo 0.102.1" /> - - <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/cpp/feed.xml" title="REPL: Rest-Eat-Program Loop" /> - - </head> - <body class="list"> - <header class="header"> - <nav class="nav"> - <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p> - </nav> - </header> - <main class="main"> - -<header class="page-header"><h1>cpp</h1></header> - -<article class="post-entry"> - <header class="entry-header"> - <h2>[C++] 属性構文の属性名にはキーワードが使える [[void]] [[for]]</h2> - </header> - <section class="entry-content"> - <p>C++ の属性構文の属性名には、キーワードが使える。ネタ記事。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2021-10-02</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/"></a> -</article></main> -<footer class="footer"> - <span>© 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span> - <span>·</span> - <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span> -</footer> -<script src="https://blog.nsfisis.dev/highlight.min.js"></script> -<script> - hljs.initHighlightingOnLoad(); -</script> -</body> -</html> - diff --git a/docs/tags/cpp/page/1/index.html b/docs/tags/cpp/page/1/index.html deleted file mode 100644 index ee45690..0000000 --- a/docs/tags/cpp/page/1/index.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <title>https://blog.nsfisis.dev/tags/cpp/</title> - <link rel="canonical" href="https://blog.nsfisis.dev/tags/cpp/"> - <meta name="robots" content="noindex"> - <meta charset="utf-8"> - <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/cpp/"> - </head> -</html> diff --git a/docs/tags/cpp17/feed.xml b/docs/tags/cpp17/feed.xml deleted file mode 100644 index b1be398..0000000 --- a/docs/tags/cpp17/feed.xml +++ /dev/null @@ -1,89 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> - <channel> - <title>cpp17 on REPL: Rest-Eat-Program Loop</title> - <link>https://blog.nsfisis.dev/tags/cpp17/</link> - <description>Recent content in cpp17 on REPL: Rest-Eat-Program Loop</description> - <generator>Hugo -- gohugo.io</generator> - <language>ja-JP</language> - <lastBuildDate>Sat, 02 Oct 2021 09:38:30 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/cpp17/feed.xml" rel="self" type="application/rss+xml" /> - <item> - <title>[C++] 属性構文の属性名にはキーワードが使える [[void]] [[for]]</title> - <link>https://blog.nsfisis.dev/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/</link> - <pubDate>Sat, 02 Oct 2021 09:38:30 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/</guid> - <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。 -元 URL: <a href="https://qiita.com/nsfisis/items/94090937bcf860cfa93b">https://qiita.com/nsfisis/items/94090937bcf860cfa93b</a></p> -<hr> -<p>タイトル落ち。まずはこのコードを見て欲しい。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e"><iostream></span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[alignas]] [[alignof]] [[and]] [[and_eq]] [[asm]] [[auto]] [[bitand]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[bitor]] [[bool]] [[break]] [[case]] [[catch]] [[char]] [[char16_t]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[char32_t]] [[class]] [[compl]] [[const]] [[const_cast]] [[constexpr]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[continue]] [[decltype]] [[default]] [[delete]] [[do]] [[double]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[dynamic_cast]] [[else]] [[enum]] [[explicit]] [[export]] [[extern]] [[false]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[final]] [[float]] [[for]] [[friend]] [[goto]] [[if]] [[inline]] [[int]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[long]] [[mutable]] [[namespace]] [[new]] [[noexcept]] [[not]] [[not_eq]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[nullptr]] [[operator]] [[or]] [[or_eq]] [[override]] [[private]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[protected]] [[public]] [[register]] [[reinterpret_cast]] [[return]] [[short]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[signed]] [[sizeof]] [[static]] [[static_assert]] [[static_cast]] [[struct]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[switch]] [[template]] [[this]] [[thread_local]] [[throw]] [[true]] [[try]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[typedef]] [[typeid]] [[typename]] [[union]] [[unsigned]]</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[virtual]] [[void]] [[volatile]] [[wchar_t]] [[while]] [[xor]] [[xor_eq]]</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">// [[using]] -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">int</span> main() { -</span></span><span style="display:flex;"><span> std<span style="color:#f92672">::</span>cout <span style="color:#f92672"><<</span> <span style="color:#e6db74">"Hello, World!"</span> <span style="color:#f92672"><<</span> std<span style="color:#f92672">::</span>endl; -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><blockquote> -<p>コンパイラのバージョン -$ clang++ –version -Apple clang version 11.0.0 (clang-1100.0.33.8) -Target: x86_64-apple-darwin19.6.0 -Thread model: posix -InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin</p> -<p>コンパイルコマンド (C++17指定) -$ clang++ –std=c++17 hoge.cpp</p> -</blockquote> -<p>この記事から得られるものはこれ以上ないので以下は蛇足になる。</p> -<p>別件で cppreference.com の <a href="https://en.cppreference.com/w/cpp/language/identifiers">identifier のページ</a> を読んでいた時、次の文が目に止まった。</p> -<blockquote> -<ul> -<li>the identifiers that are keywords cannot be used for other purposes; -<ul> -<li>The only place they can be used as non-keywords is in an attribute-token. (e.g. [[private]] is a valid attribute) (since C++11)</li> -</ul> -</li> -</ul> -</blockquote> -<p>キーワードでも属性として指定する場合は非キーワードとして使えるらしい。 -実際にやってみる。</p> -<p>同サイトの [keywords のページ] (<a href="https://en.cppreference.com/w/cpp/keyword">https://en.cppreference.com/w/cpp/keyword</a>) から一覧を拝借し、上のコードが出来上がった (C++17 においてキーワードでないものなど、一部省いている)。 -大量の警告 (unknown attribute ‘〇〇’ ignored) がコンパイラから出力されるが、コンパイルできる。</p> -<p>上のコードでは <code>[[using]]</code> をコメントアウトしているが、これは <code>using</code> キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#75715e">// using の例 -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">[[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]]</span> <span style="color:#960050;background-color:#1e0010">の糖衣構文</span> -</span></span></code></pre></div><p>C++17 の仕様も見てみる (正確には標準化前のドラフト)。</p> -<p>引用元: <a href="https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4">https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4</a></p> -<blockquote> -<p>If a keyword or an alternative token that satisfies the syntactic requirements of an identifier is contained in an attribute-token, it is considered an identifier.</p> -</blockquote> -<p>「<code>identifier</code> の構文上の要件を満たすキーワードまたは代替トークンが <code>attribute-token</code> に含まれている場合、<code>identifier</code> とみなされる」とある。どうやら間違いないようだ。</p> -<p>ところで、代替トークン (alternative token) とは <code>and</code> (<code>&</code>) や <code>bitor</code> (<code>|</code>) などのことだが、<code>identifier</code> の構文上の要件を満たさないような代替トークンなどあるのか? -疑問に思って調べたところ、代替トークンという語にはダイグラフも含まれるらしい (参考: <a href="https://timsong-cpp.github.io/cppwp/n4659/lex.digraph">同ドラフト</a>)</p> -<ul> -<li><code><%</code> → <code>{</code></li> -<li><code>%></code> → <code>}</code></li> -<li><code><:</code> → <code>[</code></li> -<li><code>:></code> → <code>]</code></li> -<li><code>%:</code> → <code>#</code></li> -<li><code>%:%:</code> → <code>##</code></li> -</ul> -<p>「<code>identifier</code> の構文上の要件を満たさないような代替トークン」はこれらが当てはまると思われる。</p> -<p>調べた感想: 字句解析器か構文解析器が辛そう</p> -]]></description> - </item> - - </channel> -</rss> diff --git a/docs/tags/cpp17/index.html b/docs/tags/cpp17/index.html deleted file mode 100644 index 3dd9d68..0000000 --- a/docs/tags/cpp17/index.html +++ /dev/null @@ -1,56 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - - <title>cpp17 | REPL: Rest-Eat-Program Loop</title> - - <meta name="description" content=""> - <meta name="author" content="nsfisis"> - - <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet"> - - <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg"> - <meta name="generator" content="Hugo 0.102.1" /> - - <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/cpp17/feed.xml" title="REPL: Rest-Eat-Program Loop" /> - - </head> - <body class="list"> - <header class="header"> - <nav class="nav"> - <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p> - </nav> - </header> - <main class="main"> - -<header class="page-header"><h1>cpp17</h1></header> - -<article class="post-entry"> - <header class="entry-header"> - <h2>[C++] 属性構文の属性名にはキーワードが使える [[void]] [[for]]</h2> - </header> - <section class="entry-content"> - <p>C++ の属性構文の属性名には、キーワードが使える。ネタ記事。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2021-10-02</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/"></a> -</article></main> -<footer class="footer"> - <span>© 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span> - <span>·</span> - <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span> -</footer> -<script src="https://blog.nsfisis.dev/highlight.min.js"></script> -<script> - hljs.initHighlightingOnLoad(); -</script> -</body> -</html> - diff --git a/docs/tags/cpp17/page/1/index.html b/docs/tags/cpp17/page/1/index.html deleted file mode 100644 index 74e12d4..0000000 --- a/docs/tags/cpp17/page/1/index.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <title>https://blog.nsfisis.dev/tags/cpp17/</title> - <link rel="canonical" href="https://blog.nsfisis.dev/tags/cpp17/"> - <meta name="robots" content="noindex"> - <meta charset="utf-8"> - <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/cpp17/"> - </head> -</html> diff --git a/docs/tags/feed.xml b/docs/tags/feed.xml deleted file mode 100644 index b2ed11e..0000000 --- a/docs/tags/feed.xml +++ /dev/null @@ -1,137 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> - <channel> - <title>Tags on REPL: Rest-Eat-Program Loop</title> - <link>https://blog.nsfisis.dev/tags/</link> - <description>Recent content in Tags on REPL: Rest-Eat-Program Loop</description> - <generator>Hugo -- gohugo.io</generator> - <language>ja-JP</language> - <lastBuildDate>Fri, 28 Oct 2022 21:55:23 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/feed.xml" rel="self" type="application/rss+xml" /> - <item> - <title>note-to-self</title> - <link>https://blog.nsfisis.dev/tags/note-to-self/</link> - <pubDate>Fri, 28 Oct 2022 21:55:23 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/tags/note-to-self/</guid> - <description><![CDATA[ ]]></description> - </item> - - <item> - <title>php</title> - <link>https://blog.nsfisis.dev/tags/php/</link> - <pubDate>Sun, 23 Oct 2022 09:54:07 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/tags/php/</guid> - <description><![CDATA[ ]]></description> - </item> - - <item> - <title>phperkaigi</title> - <link>https://blog.nsfisis.dev/tags/phperkaigi/</link> - <pubDate>Sun, 23 Oct 2022 09:54:07 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/tags/phperkaigi/</guid> - <description><![CDATA[ ]]></description> - </item> - - <item> - <title>conference</title> - <link>https://blog.nsfisis.dev/tags/conference/</link> - <pubDate>Sat, 27 Aug 2022 18:55:28 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/tags/conference/</guid> - <description><![CDATA[ ]]></description> - </item> - - <item> - <title>phpcon</title> - <link>https://blog.nsfisis.dev/tags/phpcon/</link> - <pubDate>Sat, 27 Aug 2022 18:55:28 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/tags/phpcon/</guid> - <description><![CDATA[ ]]></description> - </item> - - <item> - <title>my-programs</title> - <link>https://blog.nsfisis.dev/tags/my-programs/</link> - <pubDate>Sun, 24 Apr 2022 13:22:52 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/tags/my-programs/</guid> - <description><![CDATA[ ]]></description> - </item> - - <item> - <title>rust</title> - <link>https://blog.nsfisis.dev/tags/rust/</link> - <pubDate>Sat, 02 Oct 2021 09:39:27 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/tags/rust/</guid> - <description><![CDATA[ ]]></description> - </item> - - <item> - <title>ruby</title> - <link>https://blog.nsfisis.dev/tags/ruby/</link> - <pubDate>Sat, 02 Oct 2021 09:38:50 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/tags/ruby/</guid> - <description><![CDATA[ ]]></description> - </item> - - <item> - <title>ruby3</title> - <link>https://blog.nsfisis.dev/tags/ruby3/</link> - <pubDate>Sat, 02 Oct 2021 09:38:50 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/tags/ruby3/</guid> - <description><![CDATA[ ]]></description> - </item> - - <item> - <title>cpp</title> - <link>https://blog.nsfisis.dev/tags/cpp/</link> - <pubDate>Sat, 02 Oct 2021 09:38:30 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/tags/cpp/</guid> - <description><![CDATA[ ]]></description> - </item> - - <item> - <title>cpp17</title> - <link>https://blog.nsfisis.dev/tags/cpp17/</link> - <pubDate>Sat, 02 Oct 2021 09:38:30 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/tags/cpp17/</guid> - <description><![CDATA[ ]]></description> - </item> - - <item> - <title>vim</title> - <link>https://blog.nsfisis.dev/tags/vim/</link> - <pubDate>Sat, 02 Oct 2021 09:37:25 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/tags/vim/</guid> - <description><![CDATA[ ]]></description> - </item> - - <item> - <title>python</title> - <link>https://blog.nsfisis.dev/tags/python/</link> - <pubDate>Sat, 02 Oct 2021 09:32:37 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/tags/python/</guid> - <description><![CDATA[ ]]></description> - </item> - - <item> - <title>python3</title> - <link>https://blog.nsfisis.dev/tags/python3/</link> - <pubDate>Sat, 02 Oct 2021 09:32:37 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/tags/python3/</guid> - <description><![CDATA[ ]]></description> - </item> - - </channel> -</rss> diff --git a/docs/tags/index.html b/docs/tags/index.html deleted file mode 100644 index 79ef62b..0000000 --- a/docs/tags/index.html +++ /dev/null @@ -1,44 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - - <title>Tags | REPL: Rest-Eat-Program Loop</title> - - <meta name="description" content=""> - <meta name="author" content="nsfisis"> - - <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet"> - - <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg"> - <meta name="generator" content="Hugo 0.102.1" /> - - <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/feed.xml" title="REPL: Rest-Eat-Program Loop" /> - - </head> - <body class="list"> - <header class="header"> - <nav class="nav"> - <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p> - </nav> - </header> - <main class="main"> - -<header class="page-header"><h1>Tags</h1></header> -</main> -<footer class="footer"> - <span>© 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span> - <span>·</span> - <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span> -</footer> -<script src="https://blog.nsfisis.dev/highlight.min.js"></script> -<script> - hljs.initHighlightingOnLoad(); -</script> -</body> -</html> - diff --git a/docs/tags/my-programs/feed.xml b/docs/tags/my-programs/feed.xml deleted file mode 100644 index 34cd4bb..0000000 --- a/docs/tags/my-programs/feed.xml +++ /dev/null @@ -1,62 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> - <channel> - <title>my-programs on REPL: Rest-Eat-Program Loop</title> - <link>https://blog.nsfisis.dev/tags/my-programs/</link> - <description>Recent content in my-programs on REPL: Rest-Eat-Program Loop</description> - <generator>Hugo -- gohugo.io</generator> - <language>ja-JP</language> - <lastBuildDate>Sun, 24 Apr 2022 13:22:52 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/my-programs/feed.xml" rel="self" type="application/rss+xml" /> - <item> - <title>term-banner: ターミナルにバナーを表示するツールを書いた</title> - <link>https://blog.nsfisis.dev/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/</link> - <pubDate>Sun, 24 Apr 2022 13:22:52 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/</guid> - <description><![CDATA[ <h1 id="はじめに">はじめに</h1> -<p>こんなものを作った。</p> -<pre tabindex="0"><code>$ term-banner 'Hello, World!' 'こんにちは、' '世界!' -</code></pre><p><img src="https://raw.githubusercontent.com/nsfisis/term-banner/main/screenshot.png" alt="term-banner のスクリーンショット"></p> -<p>コマンドライン引数として渡した文字列をターミナルに大きく表示する。</p> -<p>リポジトリはこちら: <a href="https://github.com/nsfisis/term-banner">https://github.com/nsfisis/term-banner</a></p> -<h1 id="motivation">Motivation</h1> -<p>以前、<a href="https://github.com/nsfisis/big-clock-mode">big-clock-mode</a> という似たようなプログラムを書いた。 -これは tmux の <code>:clock-mode</code> コマンドに着想を得たもので、<code>:clock-mode</code> よりも大きく現在時刻を表示する。</p> -<p><code>big-clock-mode</code> を開発したのは、次のようなシチュエーションで使うためである。 -弊社では現在リモートワークが基本だが、web 会議などで画面共有しているときに、休憩を挟んで特定の時刻から再開する、ということがある。 -こういったケースで、画面上に現在の時刻を大きめに表示しておくと、モニタから離れても遠くから時刻がわかるので便利である。</p> -<p>それこそタイマアプリか何かを使えばいいのだが、ターミナルに棲むいきものとしては、住処から離れたくないわけだ。</p> -<p>しばらく便利に使っていたのだが、ひとつ不満点が出てきた。それは、再開する時刻がいつだったかを覚えておかなければならないということだ。 -どこかにメモしておいてもいいが、せっかくなら現在時刻とともに表示させておきたい。</p> -<p>そんなわけで、「任意の文字列をターミナルに表示する」プログラムを書く運びとなった。 -まあ、作らなくても探せばあると思うが、作りたいものは作りたいので知ったことではない。</p> -<h1 id="プログラム">プログラム</h1> -<p>全体の流れは次のようになっている。</p> -<ol> -<li>フォントファイルを読み込む</li> -<li>コマンドライン引数を Shift-JIS に変換する (フォントが Shift-JIS 基準で並んでいるため)</li> -<li>1文字ずつレンダリングしていく</li> -</ol> -<p><code>big-clock-mode</code> が Go 製なので、今回も Go で書いた。 -PNG が標準ライブラリにあったり、Shift-JIS のエンコーディングが準標準ライブラリにあったりしたのは助かった。</p> -<p>フォントファイルは <code>go:embed</code> で実行ファイルに埋め込んでいるので、ビルド後はワンバイナリで動く。 -仕事ではスクリプト言語ばかり書いているが、やはりコンパイル言語はいい。</p> -<h1 id="フォント">フォント</h1> -<p>フリーの 8x8 ビットマップフォントである、<a href="https://littlelimit.net/misaki.htm">美咲フォント 2021-05-05a 版</a> を使わせていただいた。</p> -<p>はじめは自分でポチポチ打っていたのだが、「き」くらいまでやって挫折した。 -同じく 8x8 で作っていたのだが、平仮名でさえも、この小さなキャンバスにはとても収められない。</p> -<p>美咲フォントは、平仮名・片仮名に留まらず、JIS 第一・第二水準の漢字までサポートしている。 -第二水準ともなると一生お目にかかることのない字の方が多いくらいだが、これをこの大きさで書くというのは、もはや芸術の域である。</p> -<p>さらに言うと、実のところ美咲フォントは実サイズ 7x7 で作られており、余白が設けられている。 -これは、単純にそのまま並べても字間・行間を確保できるようにという配慮である。 -おかげでコーディングまで楽になった。</p> -<p>ゴシック体と明朝体があったが、私の好みで明朝体の方にした。 -ただ、ゴシック体の方が見やすい気がするので、フォントを選べるように後ほど拡張するかもしれない。</p> -<p>2022-04-27 追記: <code>-f</code> オプションで選べるようにした。</p> -<h1 id="おわりに">おわりに</h1> -<p>あなたもターミナルに住んでみませんか?</p> -]]></description> - </item> - - </channel> -</rss> diff --git a/docs/tags/my-programs/index.html b/docs/tags/my-programs/index.html deleted file mode 100644 index bc71599..0000000 --- a/docs/tags/my-programs/index.html +++ /dev/null @@ -1,56 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - - <title>my-programs | REPL: Rest-Eat-Program Loop</title> - - <meta name="description" content=""> - <meta name="author" content="nsfisis"> - - <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet"> - - <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg"> - <meta name="generator" content="Hugo 0.102.1" /> - - <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/my-programs/feed.xml" title="REPL: Rest-Eat-Program Loop" /> - - </head> - <body class="list"> - <header class="header"> - <nav class="nav"> - <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p> - </nav> - </header> - <main class="main"> - -<header class="page-header"><h1>my-programs</h1></header> - -<article class="post-entry"> - <header class="entry-header"> - <h2>term-banner: ターミナルにバナーを表示するツールを書いた</h2> - </header> - <section class="entry-content"> - <p>ターミナルに任意の文字のバナーを表示するためのツールを Go で書いた。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2022-04-24</time>, updated on <time>2022-04-27</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/"></a> -</article></main> -<footer class="footer"> - <span>© 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span> - <span>·</span> - <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span> -</footer> -<script src="https://blog.nsfisis.dev/highlight.min.js"></script> -<script> - hljs.initHighlightingOnLoad(); -</script> -</body> -</html> - diff --git a/docs/tags/my-programs/page/1/index.html b/docs/tags/my-programs/page/1/index.html deleted file mode 100644 index 36f7d78..0000000 --- a/docs/tags/my-programs/page/1/index.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <title>https://blog.nsfisis.dev/tags/my-programs/</title> - <link rel="canonical" href="https://blog.nsfisis.dev/tags/my-programs/"> - <meta name="robots" content="noindex"> - <meta charset="utf-8"> - <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/my-programs/"> - </head> -</html> diff --git a/docs/tags/note-to-self/feed.xml b/docs/tags/note-to-self/feed.xml deleted file mode 100644 index 2a8f961..0000000 --- a/docs/tags/note-to-self/feed.xml +++ /dev/null @@ -1,123 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> - <channel> - <title>note-to-self on REPL: Rest-Eat-Program Loop</title> - <link>https://blog.nsfisis.dev/tags/note-to-self/</link> - <description>Recent content in note-to-self on REPL: Rest-Eat-Program Loop</description> - <generator>Hugo -- gohugo.io</generator> - <language>ja-JP</language> - <lastBuildDate>Fri, 28 Oct 2022 21:55:23 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/note-to-self/feed.xml" rel="self" type="application/rss+xml" /> - <item> - <title>[備忘録] このサイト用の VPS をセットアップしたときのメモ</title> - <link>https://blog.nsfisis.dev/posts/2022-10-28/setup-server-for-this-site/</link> - <pubDate>Fri, 28 Oct 2022 21:55:23 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2022-10-28/setup-server-for-this-site/</guid> - <description><![CDATA[ <h1 id="はじめに">はじめに</h1> -<p>これまでこの blog は GitHub Pages でホストしていたのだが、先日 VPS に移行した。そのときにおこなったサーバのセットアップ作業を書き残しておく。99 % 自分用の備忘録。別のベンダに移したりしたくなったら見に来る。</p> -<p>未来の自分へ: 特に自動化してないので、せいぜい苦しんでくれ。</p> -<h1 id="vps">VPS</h1> -<p><a href="https://vps.sakura.ad.jp/">さくらの VPS</a> の 2 GB プラン。そこまで真面目に選定していないので、困ったら移動するかも。</p> -<h1 id="事前準備">事前準備</h1> -<h2 id="サーバのホスト名を決める">サーバのホスト名を決める</h2> -<p>モチベーションが上がるという効能がある。今回は藤原定家から取って “teika” にした。たいていいつも源氏物語の帖か小倉百人一首の歌人から選んでいる。</p> -<h2 id="ssh-の鍵生成">SSH の鍵生成</h2> -<p>ローカルマシンで鍵を生成する。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ ssh-keygen -t ed25519 -b <span style="color:#ae81ff">521</span> -f ~/.ssh/teika.key -</span></span><span style="display:flex;"><span>$ ssh-keygen -t ed25519 -b <span style="color:#ae81ff">521</span> -f ~/.ssh/github2teika.key -</span></span></code></pre></div><p><code>teika.key</code> はローカルからサーバへの接続用、<code>github2teika.key</code> は、GitHub Actions からサーバへのデプロイ用。</p> -<h2 id="ssh-の設定">SSH の設定</h2> -<p><code>.ssh/config</code> に設定しておく。</p> -<pre tabindex="0"><code class="language-ssh_config" data-lang="ssh_config">Host teika - HostName ********** - User ********** - Port ********** - IdentityFile ~/.ssh/teika.key -</code></pre><h1 id="基本のセットアップ">基本のセットアップ</h1> -<h2 id="ssh-接続">SSH 接続</h2> -<p>VPS 契約時に設定した管理者ユーザとパスワードを使ってログインする。</p> -<h2 id="ユーザを作成する">ユーザを作成する</h2> -<p>管理者ユーザで作業すると危ないので、メインで使うユーザを作成する。<code>sudo</code> グループに追加して <code>sudo</code> できるようにし、<code>su</code> で切り替え。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo adduser ********** -</span></span><span style="display:flex;"><span>$ sudo adduser ********** sudo -</span></span><span style="display:flex;"><span>$ su ********** -</span></span><span style="display:flex;"><span>$ cd -</span></span></code></pre></div><h2 id="ホスト名を変える">ホスト名を変える</h2> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo hostname teika -</span></span></code></pre></div><h2 id="公開鍵を置く">公開鍵を置く</h2> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ mkdir ~/.ssh -</span></span><span style="display:flex;"><span>$ chmod <span style="color:#ae81ff">700</span> ~/.ssh -</span></span><span style="display:flex;"><span>$ vi ~/.ssh/authorized_keys -</span></span></code></pre></div><p><code>authorized_keys</code> には、ローカルで生成した <code>~/.ssh/teika.key.pub</code> と <code>~/.ssh/github2teika.key.pub</code> の内容をコピーする。</p> -<h2 id="ssh-の設定-1">SSH の設定</h2> -<p>SSH の設定を変更し、少しでも安全にしておく。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak -</span></span><span style="display:flex;"><span>$ sudo vi /etc/ssh/sshd_config -</span></span></code></pre></div><ul> -<li><code>Port</code> を変更</li> -<li><code>PermitRootLogin</code> を <code>no</code> に</li> -<li><code>PasswordAuthentication</code> を <code>no</code> に</li> -</ul> -<p>そして設定を反映。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo systemctl restart sshd -</span></span><span style="display:flex;"><span>$ sudo systemctl status sshd -</span></span></code></pre></div><h2 id="ssh-で接続確認">SSH で接続確認</h2> -<p>今の SSH セッションは閉じずに、ターミナルを別途開いて疎通確認する。セッションを閉じてしまうと、SSH の設定に不備があった場合に締め出しをくらう。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ ssh teika -</span></span></code></pre></div><h2 id="ポートの遮断">ポートの遮断</h2> -<p>デフォルトの 22 番を閉じ、設定したポートだけ空ける。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo ufw deny ssh -</span></span><span style="display:flex;"><span>$ sudo ufw allow ******* -</span></span><span style="display:flex;"><span>$ sudo ufw enable -</span></span><span style="display:flex;"><span>$ sudo ufw reload -</span></span><span style="display:flex;"><span>$ sudo ufw status -</span></span></code></pre></div><p>ここでもう一度 SSH の接続確認を挟む。</p> -<h2 id="github-用の-ssh-鍵">GitHub 用の SSH 鍵</h2> -<p>GitHub に置いてある private リポジトリをサーバから clone したいので、SSH 鍵を生成して置いておく。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ ssh-keygen -t ed25519 -b <span style="color:#ae81ff">521</span> -f ~/.ssh/github.key -</span></span><span style="display:flex;"><span>$ cat ~/.ssh/github.key.pub -</span></span></code></pre></div><p><a href="https://github.com/settings/ssh">GitHub の設定画面</a> から、この公開鍵を追加する。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ vi ~/.ssh/config -</span></span></code></pre></div><p>設定はこう。</p> -<pre tabindex="0"><code class="language-ssh_config" data-lang="ssh_config">Host github.com - HostName github.com - User git - IdentityFile ~/.ssh/github.key -</code></pre><p>最後に接続できるか確認しておく。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>ssh -T github.com -</span></span></code></pre></div><h2 id="パッケージの更新">パッケージの更新</h2> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo apt update -</span></span><span style="display:flex;"><span>$ sudo apt upgrade -</span></span><span style="display:flex;"><span>$ sudo apt update -</span></span><span style="display:flex;"><span>$ sudo apt upgrade -</span></span><span style="display:flex;"><span>$ sudo apt autoremove -</span></span></code></pre></div><h1 id="サイトホスティング用のセットアップ">サイトホスティング用のセットアップ</h1> -<h2 id="dns-に-ip-アドレスを登録する">DNS に IP アドレスを登録する</h2> -<p>このサーバは固定の IP アドレスがあるので、<code>A</code> レコードに直接入れるだけで済んだ。</p> -<h2 id="使うソフトウェアのインストール">使うソフトウェアのインストール</h2> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo apt install docker docker-compose git make -</span></span></code></pre></div><h2 id="メインユーザが-docker-を使えるように">メインユーザが Docker を使えるように</h2> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>sudo adduser ********** docker -</span></span></code></pre></div><h2 id="httphttps-を通す">HTTP/HTTPS を通す</h2> -<p>80 番と 443 番を空ける。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo ufw allow 80/tcp -</span></span><span style="display:flex;"><span>$ sudo ufw allow 443/tcp -</span></span><span style="display:flex;"><span>$ sudo ufw reload -</span></span><span style="display:flex;"><span>$ sudo ufw status -</span></span></code></pre></div><h2 id="リポジトリのクローン">リポジトリのクローン</h2> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ cd -</span></span><span style="display:flex;"><span>$ git clone git@github.com:nsfisis/nsfisis.dev.git -</span></span><span style="display:flex;"><span>$ cd nsfisis.dev -</span></span><span style="display:flex;"><span>$ git submodule update --init -</span></span></code></pre></div><h2 id="certbot-で証明書取得">certbot で証明書取得</h2> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ docker-compose up -d acme-challenge -</span></span><span style="display:flex;"><span>$ make setup -</span></span></code></pre></div><h2 id="サーバを稼動させる">サーバを稼動させる</h2> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ make serve -</span></span></code></pre></div><h1 id="感想">感想</h1> -<p>(業務でなく) 個人だと数年ぶりのサーバセットアップで、これだけでも割と時間を食ってしまった。とはいえ式年遷宮は楽しいので、これからも定期的にやっていきたい。コンテナデプロイにしたい気持ちもあるのだが、色々実験したい関係上、本物のサーバも欲しくはある。次の式年遷宮では、手順の一部だけでも自動化したいところ。</p> -]]></description> - </item> - - </channel> -</rss> diff --git a/docs/tags/note-to-self/index.html b/docs/tags/note-to-self/index.html deleted file mode 100644 index 0539b70..0000000 --- a/docs/tags/note-to-self/index.html +++ /dev/null @@ -1,57 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - - <title>note-to-self | REPL: Rest-Eat-Program Loop</title> - - <meta name="description" content=""> - <meta name="author" content="nsfisis"> - - <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet"> - - <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg"> - <meta name="generator" content="Hugo 0.102.1" /> - - <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/note-to-self/feed.xml" title="REPL: Rest-Eat-Program Loop" /> - - </head> - <body class="list"> - <header class="header"> - <nav class="nav"> - <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p> - </nav> - </header> - <main class="main"> - -<header class="page-header"><h1>note-to-self</h1></header> - -<article class="post-entry"> - <header class="entry-header"> - <h2>[備忘録] このサイト用の VPS をセットアップしたときのメモ</h2> - </header> - <section class="entry-content"> - <p>GitHub Pages でホストしていたこのサイトを VPS へ移行したので、 -そのときにやったことのメモ。99 % 自分用。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2022-10-28</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-10-28/setup-server-for-this-site/"></a> -</article></main> -<footer class="footer"> - <span>© 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span> - <span>·</span> - <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span> -</footer> -<script src="https://blog.nsfisis.dev/highlight.min.js"></script> -<script> - hljs.initHighlightingOnLoad(); -</script> -</body> -</html> - diff --git a/docs/tags/note-to-self/page/1/index.html b/docs/tags/note-to-self/page/1/index.html deleted file mode 100644 index 3d56366..0000000 --- a/docs/tags/note-to-self/page/1/index.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <title>https://blog.nsfisis.dev/tags/note-to-self/</title> - <link rel="canonical" href="https://blog.nsfisis.dev/tags/note-to-self/"> - <meta name="robots" content="noindex"> - <meta charset="utf-8"> - <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/note-to-self/"> - </head> -</html> diff --git a/docs/tags/page/1/index.html b/docs/tags/page/1/index.html deleted file mode 100644 index 2dbd4ae..0000000 --- a/docs/tags/page/1/index.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <title>https://blog.nsfisis.dev/tags/</title> - <link rel="canonical" href="https://blog.nsfisis.dev/tags/"> - <meta name="robots" content="noindex"> - <meta charset="utf-8"> - <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/"> - </head> -</html> diff --git a/docs/tags/php/feed.xml b/docs/tags/php/feed.xml deleted file mode 100644 index 32be73a..0000000 --- a/docs/tags/php/feed.xml +++ /dev/null @@ -1,1493 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> - <channel> - <title>php on REPL: Rest-Eat-Program Loop</title> - <link>https://blog.nsfisis.dev/tags/php/</link> - <description>Recent content in php on REPL: Rest-Eat-Program Loop</description> - <generator>Hugo -- gohugo.io</generator> - <language>ja-JP</language> - <lastBuildDate>Sun, 23 Oct 2022 09:54:07 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/php/feed.xml" rel="self" type="application/rss+xml" /> - <item> - <title>PHPerKaigi 2023: ボツになったトークン問題 その 1</title> - <link>https://blog.nsfisis.dev/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/</link> - <pubDate>Sun, 23 Oct 2022 09:54:07 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/</guid> - <description><![CDATA[ <h1 id="はじめに">はじめに</h1> -<p>2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) の、<a href="https://phperkaigi.jp/2023/">PHPerKaigi 2023</a> において、昨年と同様に、弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> から、トークン問題を出題予定である。</p> -<p>昨年のトークン問題の記事はこちら: <a href="/posts/2022-04-09/phperkaigi-2022-tokens">PHPerKaigi 2022 トークン問題の解説</a></p> -<p>すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。</p> -<p>10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。</p> -<h1 id="問題">問題</h1> -<p>注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#66d9ef">null</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> ($π <span style="color:#f92672">===</span> <span style="color:#66d9ef">null</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">'No input.'</span>); -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#a6e22e">trim</span>($π); -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">is_numeric</span>($π)) { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">'Invalid input.'</span>); -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>))); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">preg_match</span>(<span style="color:#e6db74">'/(\x23.+?) /'</span>, $s, $m); -</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> $m[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#e6db74">''</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">md5</span>($t) <span style="color:#f92672">===</span> <span style="color:#e6db74">'056e831a4146bf123e8ea16613303d2e'</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">"Token: </span><span style="color:#e6db74">{</span>$t<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>; -</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">else</span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">"Failed.</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>; -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><h1 id="トークン入手方法">トークン入手方法</h1> -<p>ソースを見るとわかるとおり、<code>$argv[1]</code> を参照している。それを <code>$π</code> なる変数に代入しているので、円周率を渡してみる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.14 -</span></span><span style="display:flex;"><span>Failed. -</span></span></code></pre></div><p>失敗してしまった。精度を上げてみる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.1415 -</span></span><span style="display:flex;"><span>Failed. -</span></span></code></pre></div><p>だめだった。これを成功するまで繰り返す。</p> -<p>最初にトークンが得られるのは、小数点以下 16 桁目まで入力したときで、こうなる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.1415926535897932 -</span></span><span style="display:flex;"><span>Token: #YO -</span></span></code></pre></div><p>めでたくトークン「#YO」が手に入った。</p> -<h1 id="解説">解説</h1> -<p>短いので頭から追っていく。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#66d9ef">null</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> ($π <span style="color:#f92672">===</span> <span style="color:#66d9ef">null</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">'No input.'</span>); -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#a6e22e">trim</span>($π); -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">is_numeric</span>($π)) { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">'Invalid input.'</span>); -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>入力のバリデーション部分。数値のみ受け付ける。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>))); -</span></span></code></pre></div><p><code>$π</code> を 2 文字ごとに区切り (<code>str_split</code>)、数値を ASCII コードと見做して文字に変換 (<code>chr</code>) して結合 (<code>implode</code>) している。</p> -<p>例えば、<code>$π</code> が <code>'656667'</code> だったとすると、<code>65</code>、<code>66</code>、<code>67</code> に対応した <code>'A'</code>、<code>'B'</code>、<code>'C'</code> へと変換され、<code>'ABC'</code> になる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#e6db74">'656667'</span>; -</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>))); -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> $s; -</span></span><span style="display:flex;"><span><span style="color:#75715e">// => ABC -</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">preg_match</span>(<span style="color:#e6db74">'/(\x23.+?) /'</span>, $s, $m); -</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> $m[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#e6db74">''</span>; -</span></span></code></pre></div><p>正規表現でマッチングしている。<code>\x23</code> は <code>#</code> と同じであることに留意すると、この正規表現は「<code>#</code> から始まる 2 以上の長さ (含 <code>#</code>) の文字列で、最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi におけるトークンである。</p> -<p>なお、<code>#</code> を直接書いていないのは、<code>/#.+?) /</code> と書くと、<code>#.+?)</code> という意図せぬトークンが登録されてしまうからである。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">md5</span>($t) <span style="color:#f92672">===</span> <span style="color:#e6db74">'056e831a4146bf123e8ea16613303d2e'</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">"Token: </span><span style="color:#e6db74">{</span>$t<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>; -</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">else</span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">"Failed.</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>; -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>最後にトークンのハッシュ値を見て、想定解かどうかを確認する。</p> -<h1 id="おわりに">おわりに</h1> -<p>円周率を何桁も計算して ASCII コード経由で文字列化すれば、トークンっぽいものがどこかで出てくるのではないか、と考えて生まれた作品。</p> -<p>最初は真面目に円周率の計算プログラムを組んでいたのだが、いざ動かしてみるとやけに浅いところにあったので驚いた (ちなみに、それでも <code>M_PI</code> や <code>pi()</code> では精度が足りない)。見つけたときは狂喜したものの、冷静になってみると大して面白くなかったのでボツになった。むしろ、100 万桁目くらいに埋まっていてくれたほうがよかったかもしれない。</p> -]]></description> - </item> - - <item> - <title>[PHP] fizzbuzz を書く。1行あたり2文字で。</title> - <link>https://blog.nsfisis.dev/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/</link> - <pubDate>Thu, 29 Sep 2022 00:50:52 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/</guid> - <description><![CDATA[ <h1 id="記事の構成について">記事の構成について</h1> -<p>この記事は、普通の fizzbuzz を徐々に変形して最終形にしていく、という構成で書かれている。最終形を見てどのような仕組みで動いているのか解読してから解説を読みたい、というかたがいれば、 <a href="https://gist.github.com/nsfisis/04c227d5a419867472a0b23a83ad2919#file-fizzbuzz-php-2-letters-per-line-and-supports-php-8-x-without-warnings">このページ</a> にソースコードがあるので、そちらを先に見てほしい。</p> -<h1 id="レギュレーション">レギュレーション</h1> -<p>PHP で、次のような制約の下に fizzbuzz を書いた。</p> -<ul> -<li>1行あたりの文字数は2文字までに収めること (ただし <code><?php</code> タグは除く) -<ul> -<li>厳密な定義: <code><?php</code> タグ以降のソースコードが、2 byte ごとに ラインフィード (LF) で区切られること</li> -</ul> -</li> -<li>スペースやタブを使用しないこと</li> -<li>ループのアンロールをしないこと -<ul> -<li>100 回ループの代わりに 100 回コードをコピペ、というのは禁止</li> -</ul> -</li> -<li>PHP 7.4〜8.1 で動作すること</li> -<li>実行時に Notice や Warning が出ないこと</li> -<li>標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと)</li> -</ul> -<p>備考: PHP には <code>short_open_tag</code> というオプションがあり、これを有効にするとファイル冒頭の <code><?php</code> の代わりに <code><?</code> を使うことができ、文字どおり1行2文字で書ける。ただ、このオプションはデフォルト off になっている環境が多いようなので、今回は使わないことにした。</p> -<h1 id="主な障害">主な障害</h1> -<p>1行あたりの文字数など、適当に改行を挟めばいいだけではないのか?</p> -<p>特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">#\ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">i\ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">n\ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">c\ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">l\ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">u\ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">d\ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">e\ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"><\ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">s\ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">t\ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">d\ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">i\ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">o\ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">.\ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">h\ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">>\ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">*/</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>i\ -</span></span><span style="display:flex;"><span>n\ -</span></span><span style="display:flex;"><span>t\ -</span></span><span style="display:flex;"><span><span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">*/</span> -</span></span><span style="display:flex;"><span>m\ -</span></span><span style="display:flex;"><span>a\ -</span></span><span style="display:flex;"><span>i\ -</span></span><span style="display:flex;"><span>n( -</span></span><span style="display:flex;"><span>){ -</span></span><span style="display:flex;"><span>f\ -</span></span><span style="display:flex;"><span>o\ -</span></span><span style="display:flex;"><span>r( -</span></span><span style="display:flex;"><span>i\ -</span></span><span style="display:flex;"><span>n\ -</span></span><span style="display:flex;"><span>t\ -</span></span><span style="display:flex;"><span><span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">*/</span> -</span></span><span style="display:flex;"><span>i<span style="color:#f92672">=</span> -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span>; -</span></span><span style="display:flex;"><span>i<span style="color:#f92672"><</span> -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span>\ -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0</span>\ -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0</span>; -</span></span><span style="display:flex;"><span>i\ -</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span>\ -</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span>) -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> -</span></span><span style="display:flex;"><span>(i -</span></span><span style="display:flex;"><span><span style="color:#f92672">%</span>\ -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">15</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">==</span> -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0</span>) -</span></span><span style="display:flex;"><span>p\ -</span></span><span style="display:flex;"><span>r\ -</span></span><span style="display:flex;"><span>i\ -</span></span><span style="display:flex;"><span>n\ -</span></span><span style="display:flex;"><span>t\ -</span></span><span style="display:flex;"><span>f( -</span></span><span style="display:flex;"><span><span style="color:#e6db74">"\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">F\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">i\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">z\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">z\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">B\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">u\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">z\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">z\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">c\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">"</span>, -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">10</span> -</span></span><span style="display:flex;"><span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">/* あとは同じように普通のプログラムを変形するだけなので省略 */</span> -</span></span></code></pre></div><p>バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。</p> -<p>さて、PHP ではそもそもバックスラッシュを行継続に使うことができない。これにより、「3文字以上からなるトークンが一切使えない」という制約が課される。例えば、<code>echo</code> で出力することや、<code>for</code> でループすること、<code>new</code> でインスタンスを生成することができない。特に、出力は fizzbuzz をどんなアルゴリズムで実装しようとおこなわなければならないので、できないのは致命的である。</p> -<p>当然、名前が3文字以上ある関数も使えない。なお、標準 PHP の範囲内において、名前が 2文字以下の関数は以下のとおりである:</p> -<ul> -<li><code>_</code>: <code>gettext</code> のエイリアス</li> -<li><code>dl</code>: 拡張モジュールをロードする</li> -<li><code>pi</code>: 円周率を返す</li> -</ul> -<p>(環境によって多少は変わるかも)</p> -<p>2文字の関数を定義しまくった拡張モジュールを用意しておいて <code>dl()</code> で読み込む行為は、レギュレーションで定めた</p> -<blockquote> -<ul> -<li>標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと)</li> -</ul> -</blockquote> -<p>に反する (というより、「それだとおもしろくもなんともないので、このルールを足した」というのが正しい)。</p> -<p>また、2文字だと文字列がまともに書けないのも辛い。<code>''</code> だけで 2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP では文字列リテラル中に生の改行が書けるので</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$a -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">' -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">a'</span> -</span></span><span style="display:flex;"><span>;; -</span></span></code></pre></div><p>とすると <code>$a</code> は <code>"\na"</code> になるのだが、余計な改行が入ってしまう。</p> -<p>これらの障害をどのように乗り越えるのか、次節から見ていく。</p> -<h1 id="解説">解説</h1> -<h2 id="普通の--fizzbuzz">普通の (?) fizzbuzz</h2> -<p>まずは普通に書くとしよう。</p> -<pre tabindex="0"><code><?php - -for ($i = 1; $i < 100; $i++) { - echo (($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"; -} -</code></pre><p>素直に書いた fizzbuzz とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。</p> -<h2 id="for-の排除"><code>for</code> の排除</h2> -<p><code>for</code> は、3文字もある長いキーワードである。こんなものは使えない。<code>array_</code> 系の関数を使って、適当に置き換えるとしよう。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">range</span>(<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">100</span>); -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">array_walk</span>( -</span></span><span style="display:flex;"><span> $s, -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fn</span>($i) <span style="color:#f92672">=></span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">printf</span>((($i <span style="color:#f92672">%</span> <span style="color:#ae81ff">3</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">''</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">'Fizz'</span>) <span style="color:#f92672">.</span> ($i <span style="color:#f92672">%</span> <span style="color:#ae81ff">5</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">''</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">'Buzz'</span>) <span style="color:#f92672">?:</span> $i) <span style="color:#f92672">.</span> <span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>), -</span></span><span style="display:flex;"><span>); -</span></span></code></pre></div><p><code>array_walk</code> や <code>range</code>、<code>printf</code> といった <code>for</code> よりも長いトークンが現れてしまったが、これは次節で直すことにする。なお、<code>echo</code> は文 (statement) であり式 (expression) ではないので、式である <code>printf</code> に置き換えた。</p> -<h2 id="関数呼び出しの短縮">関数呼び出しの短縮</h2> -<p><code>range</code>、<code>array_walk</code>、<code>printf</code> は長すぎるのでどうにかせねばならない。ここで、PHP の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$r <span style="color:#f92672">=</span> <span style="color:#e6db74">'range'</span>; -</span></span><span style="display:flex;"><span>$w <span style="color:#f92672">=</span> <span style="color:#e6db74">'array_walk'</span>; -</span></span><span style="display:flex;"><span>$p <span style="color:#f92672">=</span> <span style="color:#e6db74">'printf'</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> $r(<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">100</span>); -</span></span><span style="display:flex;"><span>$w( -</span></span><span style="display:flex;"><span> $s, -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fn</span>($i) <span style="color:#f92672">=></span> -</span></span><span style="display:flex;"><span> $p((($i <span style="color:#f92672">%</span> <span style="color:#ae81ff">3</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">''</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">'Fizz'</span>) <span style="color:#f92672">.</span> ($i <span style="color:#f92672">%</span> <span style="color:#ae81ff">5</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">''</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">'Buzz'</span>) <span style="color:#f92672">?:</span> $i) <span style="color:#f92672">.</span> <span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>), -</span></span><span style="display:flex;"><span>); -</span></span></code></pre></div><p>これで関数を呼び出している所は短くなった。では、<code>$r</code> や <code>$w</code> や <code>$p</code>、また <code>'Fizz'</code> や <code>'Buzz'</code> はどうやって 1行2文字に収めるのか。次のテクニックへ移ろう。</p> -<h2 id="余談-php-8x-で動作しなくてもいいなら">余談: PHP 8.x で動作しなくてもいいなら</h2> -<p>今回使ったテクニックを説明する前に、余談として、文字列リテラルの短縮法として今回採用しなかったものを紹介する。</p> -<blockquote> -<ul> -<li>PHP 7.4〜8.1 で動作すること</li> -</ul> -</blockquote> -<p>というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という PHP 7.x までの仕様が利用できる。例えば、 <code>Fizz</code> という文字列が欲しければ、次のようにする。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$f -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#a6e22e">F</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#a6e22e">i</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#a6e22e">z</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#a6e22e">z</span> -</span></span><span style="display:flex;"><span>;; -</span></span></code></pre></div><p>こうして簡単に文字列を作れる。なお、この仕様は 7.x 時点でも警告を受けるので、<code>@</code> 演算子を使って抑制してやるとよい。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$f -</span></span><span style="display:flex;"><span><span style="color:#f92672">=@</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">F</span><span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">@</span><span style="color:#a6e22e">i</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">@</span><span style="color:#a6e22e">z</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">@</span><span style="color:#a6e22e">z</span> -</span></span><span style="display:flex;"><span>;; -</span></span></code></pre></div><p>むしろ、このことがわかっていたからこそ PHP 8.x での動作を要件に課したところがある。</p> -<h2 id="文字列リテラルの短縮">文字列リテラルの短縮</h2> -<p>実際に使った手法の説明に移る。</p> -<p>ずばり、文字列同士のビット演算を使う。PHP では、文字列同士でビット演算 (<code>&</code>、<code>|</code>、<code>^</code>) をした場合、文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$a <span style="color:#f92672">=</span> <span style="color:#e6db74">"12345"</span>; -</span></span><span style="display:flex;"><span>$b <span style="color:#f92672">=</span> <span style="color:#e6db74">"world"</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">// $a ^ $b は次のコードと同じ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$result <span style="color:#f92672">=</span> <span style="color:#e6db74">''</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> ($i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; $i <span style="color:#f92672"><</span> <span style="color:#a6e22e">min</span>(<span style="color:#a6e22e">strlen</span>($a), <span style="color:#a6e22e">strlen</span>($b)); $i<span style="color:#f92672">++</span>) { -</span></span><span style="display:flex;"><span> $result <span style="color:#f92672">.=</span> $a[$i] <span style="color:#f92672">^</span> $b[$i]; -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> $result; -</span></span><span style="display:flex;"><span><span style="color:#75715e">// => F]AXQ -</span></span></span></code></pre></div><p>これを踏まえ、次のコードを見てみよう。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#e6db74">"x</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">Om</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>; -</span></span><span style="display:flex;"><span>$y <span style="color:#f92672">=</span> <span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">k!</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">o"</span>; -</span></span><span style="display:flex;"><span>$r <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> $y; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">"</span><span style="color:#e6db74">$r\n</span><span style="color:#e6db74">"</span>; -</span></span></code></pre></div><p>実行すると、<code>range</code> が表示される。さて、PHP では文字列リテラル中に生の改行を直接書いてもよいのだった (「主な障害」の節を参照のこと)。書きかえてみよう。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$x -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">'x -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Om -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">'</span>; -</span></span><span style="display:flex;"><span>$y -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">' -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">k! -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o'</span> -</span></span><span style="display:flex;"><span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$r <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> $y; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">"</span><span style="color:#e6db74">$r\n</span><span style="color:#e6db74">"</span>; -</span></span></code></pre></div><p>さらに <code>#</code> を使って適当に調整すると、次のようになる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$x -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">'x -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Om -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">'</span>; -</span></span><span style="display:flex;"><span>$y -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">' -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">k! -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o'</span> -</span></span><span style="display:flex;"><span>;<span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$r -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x -</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y -</span></span><span style="display:flex;"><span>;<span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">"</span><span style="color:#e6db74">$r\n</span><span style="color:#e6db74">"</span>; -</span></span></code></pre></div><p>1行あたり2文字で、<code>range</code> という文字列を生成することに成功した。他の必要な文字列にも、同様の処理をほどこす。</p> -<p>備考: <code>Buzz</code> 中にある小文字の <code>u</code> は、このロジックだと non-printable な文字になってしまう。ここまでのテクニックを駆使すれば回避するのはそう難しくないので、考えてみてほしい。</p> -<h1 id="完成系">完成系</h1> -<p>完成したものがこちら。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$x -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">'i -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">S'</span> -</span></span><span style="display:flex;"><span>;; -</span></span><span style="display:flex;"><span>$y -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">' -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">b! -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">'</span>; -</span></span><span style="display:flex;"><span>$c -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x -</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y -</span></span><span style="display:flex;"><span>;<span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">'x -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Om -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">'</span>; -</span></span><span style="display:flex;"><span>$y -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">' -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">k! -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o'</span> -</span></span><span style="display:flex;"><span>;<span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$r -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x -</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y -</span></span><span style="display:flex;"><span>;<span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">'k -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Sk -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">~} -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Ma -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">'</span>; -</span></span><span style="display:flex;"><span>$y -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">' -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">x! -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">s! -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">k! -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">'</span>; -</span></span><span style="display:flex;"><span>$w -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x -</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y -</span></span><span style="display:flex;"><span>;<span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">'z -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Hd -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">G'</span> -</span></span><span style="display:flex;"><span>;<span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">' -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">x! -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">~! -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">'</span>; -</span></span><span style="display:flex;"><span>$p -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x -</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y -</span></span><span style="display:flex;"><span>;<span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">'L -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">[p -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">'</span>; -</span></span><span style="display:flex;"><span>$y -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">' -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">c! -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">'</span>; -</span></span><span style="display:flex;"><span>$f -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x -</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y -</span></span><span style="display:flex;"><span>;<span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">'H -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">[p -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">'</span>; -</span></span><span style="display:flex;"><span>$y -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">' -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">_! -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">'</span>; -</span></span><span style="display:flex;"><span>$b -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x -</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y -</span></span><span style="display:flex;"><span>;<span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$b -</span></span><span style="display:flex;"><span>[<span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>]<span style="color:#f92672">=</span> -</span></span><span style="display:flex;"><span>$c -</span></span><span style="display:flex;"><span>(<span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#ae81ff">13</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">*</span><span style="color:#ae81ff">9</span> -</span></span><span style="display:flex;"><span>); -</span></span><span style="display:flex;"><span>$s -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$r -</span></span><span style="display:flex;"><span>(<span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>,( -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">10</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">**</span> -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2</span>) -</span></span><span style="display:flex;"><span>); -</span></span><span style="display:flex;"><span>$w -</span></span><span style="display:flex;"><span>(<span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$s -</span></span><span style="display:flex;"><span>,<span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">fn</span> -</span></span><span style="display:flex;"><span>(<span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$i -</span></span><span style="display:flex;"><span>)<span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">=></span> -</span></span><span style="display:flex;"><span>$p -</span></span><span style="display:flex;"><span>(( -</span></span><span style="display:flex;"><span>(<span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$i -</span></span><span style="display:flex;"><span><span style="color:#f92672">%</span><span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">?</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">''</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">:</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$f -</span></span><span style="display:flex;"><span>)<span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span>(<span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$i -</span></span><span style="display:flex;"><span><span style="color:#f92672">%</span><span style="color:#ae81ff">5</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">?</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">''</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">:</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$b -</span></span><span style="display:flex;"><span>)<span style="color:#f92672">?</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">:</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$i -</span></span><span style="display:flex;"><span>)<span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">.</span><span style="color:#e6db74">' -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">'</span>) -</span></span><span style="display:flex;"><span>); -</span></span></code></pre></div><h1 id="感想など">感想など</h1> -<p>PHP は、スクリプト言語の中だとシンタックスシュガーが少ない (体感)。この挑戦は不可能に思われたが、PHP マニュアルとにらめっこしていたらなんとかなった。</p> -<p>みんなもプログラムを細長くしよう。</p> -<h1 id="余談2-別解">余談2: 別解</h1> -<p>PHP では、バッククォートを使ってシェルを呼び出せる。これは <code>shell_exec</code> 関数と等価である。さて、PHP ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える (当然だが、呼び出されるシェルに依存する。Bash なら大丈夫だろう。知らんけど)。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">printf</span>(<span style="color:#e6db74">` -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">e\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">c\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">h\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> \ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">1\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">2\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">3\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">`</span>); -</span></span></code></pre></div><p>なお、ここでは簡単のため出力に <code>printf</code> をそのまま使っているが、実際には <code>printf</code> という文字列を合成して可変関数で呼び出す。</p> -<p>ただし、これでは</p> -<blockquote> -<ul> -<li>スペースやタブを使用しないこと</li> -</ul> -</blockquote> -<p>に違反してしまう。スペースが使えないと引数とコマンドを区切れない。これは困った。</p> -<p>もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$c <span style="color:#f92672">=</span> <span style="color:#e6db74">'chr'</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">$</span>{ -</span></span><span style="display:flex;"><span><span style="color:#e6db74">'_ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">'</span>} -</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$c -</span></span><span style="display:flex;"><span>(<span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#ae81ff">32</span> -</span></span><span style="display:flex;"><span>)<span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span>$c -</span></span><span style="display:flex;"><span>(<span style="color:#75715e"># -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#ae81ff">92</span> -</span></span><span style="display:flex;"><span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">printf</span>(<span style="color:#e6db74">` -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">e\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">c\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">h\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">${ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">'_ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">'} -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">1\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">2\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">3\ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">`</span>); -</span></span></code></pre></div><p>先程と同じく、<code>chr</code> や <code>printf</code> を生成する部分は長くなるので省いた。</p> -<pre tabindex="0"><code>${ -'_ -'} -</code></pre><p>は変数で、中にはスペースとエスケープが入っている (<code>chr(32) . chr(92)</code>)。シェルに渡されている文字列は次のようになる。</p> -<pre tabindex="0"><code>e\ -c\ -h\ -o\ - \ -1\ -2\ -3\ -</code></pre><p>これは、前掲したコマンドと同じだ。かくして、スペースを陽に書かずにシェルをおおよそ自由に扱えるようになった。Fizzbuzz のワンライナーくらいすぐ書けるだろうから、あとはなんとかなるだろう (試してないけど)。</p> -<p>ということでこれは別解ということにしておく。</p> -<p>ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。</p> -<pre tabindex="0"><code>${ -'_ -'} -</code></pre><p>最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。</p> -]]></description> - </item> - - <item> - <title>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</title> - <link>https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/</link> - <pubDate>Sat, 27 Aug 2022 18:55:28 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/</guid> - <description><![CDATA[ <h1 id="はじめに">はじめに</h1> -<p>本日 <a href="https://phpcon.okinawa.jp/">PHP カンファレンス沖縄 2022</a> が開催された (らしい)。</p> -<p>カンファレンスには参加できなかったものの、懇親会の LT で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。</p> -<p>ツイート: <a href="https://twitter.com/m3m0r7/status/1563397620231712772">https://twitter.com/m3m0r7/status/1563397620231712772</a> <br> -スライド: <a href="https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3">https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3</a></p> -<h1 id="解">解</h1> -<p>細かいレギュレーションは不明だったので、勝手に定めた。</p> -<ul> -<li>コマンドライン引数の第1引数で受けとる</li> -<li>結果は標準出力に出す</li> -<li>コンマの直後にはスペースを1つ置く</li> -<li>末尾コンマは禁止</li> -<li>数字でないものは入ってこないものとする</li> -<li>負数は入ってこないものとする</li> -</ul> -<p>書いたものがこちら:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>[<span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> $n<span style="color:#f92672">=</span>$argv[<span style="color:#ae81ff">1</span>];<span style="color:#66d9ef">foreach</span>([<span style="color:#ae81ff">1e4</span>,<span style="color:#ae81ff">5e3</span>,<span style="color:#ae81ff">2e3</span>,<span style="color:#ae81ff">1e3</span>,<span style="color:#ae81ff">500</span>,<span style="color:#ae81ff">100</span>,<span style="color:#ae81ff">50</span>,<span style="color:#ae81ff">10</span>,<span style="color:#ae81ff">5</span>,<span style="color:#ae81ff">1</span>]<span style="color:#66d9ef">as</span>$x)<span style="color:#66d9ef">for</span>(;$n<span style="color:#f92672">>=</span>$x;$n<span style="color:#f92672">-=</span>$x)$r[]<span style="color:#f92672">=</span>$x;<span style="color:#66d9ef">echo</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">', '</span>,$r<span style="color:#f92672">??</span>[]);<span style="color:#75715e">?></span><span style="color:#960050;background-color:#1e0010">] -</span></span></span></code></pre></div><p>しめて 123 バイトとなった (末尾改行を含めずにカウント)。</p> -<p>こちらは改行とスペースを追加したバージョン:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>[<span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$n <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>]; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ([<span style="color:#ae81ff">1e4</span>, <span style="color:#ae81ff">5e3</span>, <span style="color:#ae81ff">2e3</span>, <span style="color:#ae81ff">1e3</span>, <span style="color:#ae81ff">500</span>, <span style="color:#ae81ff">100</span>, <span style="color:#ae81ff">50</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">1</span>] <span style="color:#66d9ef">as</span> $x) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> (; $n <span style="color:#f92672">>=</span> $x; $n <span style="color:#f92672">-=</span> $x) -</span></span><span style="display:flex;"><span> $r[] <span style="color:#f92672">=</span> $x; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">', '</span>, $r <span style="color:#f92672">??</span> []); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">?></span><span style="color:#960050;background-color:#1e0010">] -</span></span></span></code></pre></div><h1 id="使用したテクニック">使用したテクニック</h1> -<h2 id="指数表記">指数表記</h2> -<p>割と多くの言語のゴルフで使えるテクニック。<code>e</code> を用いた指数表記で、大きな数を短く表す。このコードでは <code>10000</code>、<code>5000</code>、<code>2000</code>、<code>1000</code> を指数表記している。</p> -<h2 id="foreach-や-for-の中身を1つの文に">foreach や for の中身を1つの文に</h2> -<p><code>foreach</code>、<code>for</code>、<code>if</code> などの後ろには、通常 <code>{</code> を続けて複数の文を連ねるが、中身の文を1つにしてしまえば、<code>{</code> と <code>}</code> を省略できる。C言語などでも使える。</p> -<h2 id="r-に初期値を入れない">$r に初期値を入れない</h2> -<p>PHP では、<code>$r[] = ...</code> のような配列の末尾に追加する式を実行したとき、<code>$r</code> が未定義だった場合は <code>$r</code> を勝手に定義して空の配列で初期化してくれる。これを利用すると、<code>$r = [];</code> のような初期化が不要になる。</p> -<p>ただし、プログラムに 0 が渡されるとループを一度も回らないので、<code>$r</code> が未定義になってしまい、<code>implode()</code> に渡すところでエラーになる。それを防ぐために <code>$r ?? []</code> を使っている。</p> -<p>もし 0 が渡されたケースを無視するなら、これが不要になるので 4 バイト縮む。</p> -<h2 id="php-タグの外に文字列を置く">PHP タグの外に文字列を置く</h2> -<p>PHP では、<code><?php</code> <code>?></code> で囲われた部分の外側にある文字列は、そのまま出力される。今回のケースでは、先頭と末尾に必ず <code>[</code> と <code>]</code> を出力するので、そのまま書いてやればよい。</p> -<h1 id="おわりに">おわりに</h1> -<p>最後になりましたが、<a href="https://twitter.com/m3m0r7">めもりー</a> さん、楽しい問題をありがとうございました。</p> -]]></description> - </item> - - <item> - <title>PHPerKaigi 2022</title> - <link>https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/</link> - <pubDate>Sun, 01 May 2022 09:41:39 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/</guid> - <description><![CDATA[ <h1 id="はじめに">はじめに</h1> -<p>2022-04-09 から 2022-04-11 にかけて開催された、<a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> に、一般参加者として参加した。 -弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p> -<p>昨年のレポートは<a href="/posts/2021-03-30/phperkaigi-2021">こちら</a>。</p> -<h1 id="感想">感想</h1> -<h2 id="厳選おすすめトーク">厳選おすすめトーク</h2> -<p>多くの素晴らしいトークの中から、特におすすめのものを 5つ選んだ。是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。</p> -<p><a href="https://fortee.jp/phperkaigi-2022/proposal/ef8cf4ed-63fe-42f8-8145-b3e70054458b">予防に勝る防御なし - 堅牢なコードを導く様々な設計のヒント</a></p> -<blockquote> -<p>PHP はバージョンを追う毎に型宣言、例外、表明、列挙型などの機能が大幅に強化され、堅牢なコードを書くための機能が充実してきました。それらの機能はどう使うと効果的なのでしょうか。</p> -<p>本講演では PHP 8.1 をベースにして、誤りを想定してチェックするのではなく、そもそも誤りにくい設計とはどのようなものか、つまり「予防」の観点を軸足に、堅牢なコードを導くための様々な設計のヒントをご紹介します。</p> -</blockquote> -<p><a href="https://fortee.jp/phperkaigi-2022/proposal/db00d49e-0dd6-453f-b54b-f731d112f10e">PHPのエラーを理解して適切なエラーハンドリングを学ぼう</a></p> -<blockquote> -<p>PHPを使ってるとよく遭遇する Fatal error / Parse error / Warning / Notice 理解していますか?<br> -これらのエラー文を理解することで、すぐにエラーの原因に気付き適切に対象できる様になります!<br> -またそれらを理解した上でのエラーハンドリングを学びましょう。</p> -</blockquote> -<p><a href="https://fortee.jp/phperkaigi-2022/proposal/4a7e3ded-9134-4919-955c-ec7bf4491c0d">エラー監視とテスト体制への改善作戦</a></p> -<blockquote> -<p>毎日流れてくるエラーに皆さんはどう向き合ってますか?<br> -エラーを出さない事が一番ですが、完全に塞ぐ事は難しいと考えます。<br> -サービス運用の中で本番環境から発生するエラー(サーバー・クライアントサイド・サードパーティ起因のエラー)への監視体制と、<br> -エラー・バグ防御のためチームで行っているテストコード文化づくりの話をします。</p> -</blockquote> -<p><a href="https://fortee.jp/phperkaigi-2022/proposal/6f47daf8-c78f-4fb1-9b99-e9656e6fe7f7">ISUCON11のPHP実装は、何を考え、どのようにして作られていたのか</a></p> -<blockquote> -<p>昨年開催されたISUCON11にて問題(参考実装)のPHPへの移植を担当させていただきました。</p> -<p>最終的なソースコードこそシンプルなWebアプリケーションではありますが、その裏には<br> -・「(私の思う)良い設計」を実現するための意思決定<br> -・「ISUCONの問題」という位置付けに由来する取捨選択<br> -・移植中に遭遇したトラブルとその解決策<br> -といった文脈や葛藤が存在しています。</p> -<p>本発表はそれらを共有することで<br> -・PHPアプリケーションの設計、実装事例として役立ててもらう<br> -・ISUCONの言語移植に興味を持ってもらう<br> -・ISUCON問題移植の「実装や設計の練習をする教材」としての可能性を知ってもらう<br> -ことを目的とします。</p> -</blockquote> -<p><a href="https://fortee.jp/phperkaigi-2022/proposal/5a260e4e-542d-4d82-849d-ef3d6cb7c854">チームの仕事はまわっていたけど、メンバーはそれぞれモヤモヤを抱えていた話──40名の大規模開発チームで1on1ログを公開してみた</a></p> -<blockquote> -<p>サイボウズの大企業向けグループウェアのGaroon(ガルーン)は、PHPで開発されている20年目の製品です。ガルーン開発チームは日本で40名、ベトナムで50名の計90名ほどのチームになっています。また、コロナ禍でフルリモートでの活動がこの2年ほど継続してきました。</p> -<p>フルリモートになっても仕事はまわっており、継続的にリリースはしていましたが、一方でお互いの考えていることや感じている問題意識が見えづらくなり、モヤモヤを抱えているメンバーが増えていました。</p> -<p>このセッションでは、そういう状況で私がチーム外からジョインし、聴き役に徹しながら見える化することで状況を改善していった取り組みを紹介します。同じように大きなチームやリモートワークで難しさを感じている人に、難しさの原因への気づきや取り組みへのヒントがあれば幸いです。</p> -</blockquote> -<h2 id="トークン問題の作成">トークン問題の作成</h2> -<p>今回は、PHPer チャレンジ用に弊社のトークン問題を 3題作成した。こちらについては<a href="/posts/2022-04-09/phperkaigi-2022-tokens">別途記事にしている</a>ので、そちらを参照されたい。</p> -<h2 id="phper-チャレンジ">PHPer チャレンジ</h2> -<p><a href="https://fortee.jp/phperkaigi-2022/challenge">1位</a>になった。<br> -また、賞品として <a href="https://www.amazon.co.jp/dp/B08MQNJC9Z">Echo Show 15</a> をいただいた。</p> -<h2 id="カンファレンス全体への感想">カンファレンス全体への感想</h2> -<p><a href="/posts/2021-03-30/phperkaigi-2021">去年の参加レポ</a> では、こんなことを書いた。</p> -<blockquote> -<p>1つ個人的な反省点としては、(中略) Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。<br> -まあ初カンファレンスだし、とお茶を濁しておこう。</p> -</blockquote> -<p>この反省を踏まえ、今年は積極的にほかの場 (公式の Discord サーバや、アンカンファレンス) にも参加した。<br> -これにより、参加体験の質がはるかに向上した。特に Discord に関しては、登壇者ご本人による補足や、質問への回答などがおこなわれる (ことが多い) ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。</p> -<p>なお、アンカンファレンスについては、1日目の終わりに<a href="https://fortee.jp/phperkaigi-2022/unconference/view/d332797a-8921-4706-a7e2-ee72640c9b5e">トークン問題の解説放送</a>もおこなった。</p> -<p>また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。 -今年は 3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。</p> -<h1 id="そして来年へ">そして来年へ……?</h1> -<p>PHPerKaigi 2023 があるかどうか存じ上げないが、あるとすれば、次の 4つを目標としたい。</p> -<ul> -<li>プロポーザルを出す</li> -<li>PHPer チャレンジのトークン問題を 5題作成する</li> -<li>現地に行く</li> -<li>PHPer チャレンジで圧勝する</li> -</ul> -<hr> -<p>最後になりましたが、PHPerKaigi のスタッフ、スポンサー、スピーカーのみなさん、素敵な時間をありがとうございました。</p> -<p>ではまた来年。</p> -]]></description> - </item> - - <item> - <title>PHPerKaigi 2022 トークン問題の解説</title> - <link>https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/</link> - <pubDate>Sat, 09 Apr 2022 21:50:19 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/</guid> - <description><![CDATA[ <h1 id="はじめに">はじめに</h1> -<p>本日開始された <a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> の PHPer チャレンジにおいて、弊社 <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> の問題を 3問作成した。この記事では、これらの問題の解説をおこなう。</p> -<p>リポジトリはこちら: <a href="https://github.com/nsfisis/PHPerKaigi2022-tokens">https://github.com/nsfisis/PHPerKaigi2022-tokens</a></p> -<h1 id="第1問-brainf_ckphp">第1問 brainf_ck.php</h1> -<p>ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">declare</span>(<span style="color:#a6e22e">strict_types</span><span style="color:#f92672">=</span><span style="color:#ae81ff">0</span><span style="color:#a6e22e">O1</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">namespace</span> <span style="color:#a6e22e">Dgcircus\PHPerKaigi\Y2022</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#e6db74">/** -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * @todo -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Run this program to acquire a PHPer token. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> */</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">https</span><span style="color:#f92672">://</span><span style="color:#a6e22e">creativecommons</span><span style="color:#f92672">.</span><span style="color:#a6e22e">org</span><span style="color:#f92672">/</span><span style="color:#a6e22e">publicdomain</span><span style="color:#f92672">/</span><span style="color:#a6e22e">zero</span><span style="color:#f92672">/</span><span style="color:#ae81ff">1.0</span><span style="color:#f92672">/</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">\error_reporting</span>(<span style="color:#f92672">~+!</span><span style="color:#e6db74">'We are hiring!'</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$z <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($f) <span style="color:#f92672">=></span> (<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=></span> $f(<span style="color:#a6e22e">fn</span>(<span style="color:#f92672">...</span>$xs) <span style="color:#f92672">=></span> $x($x)(<span style="color:#f92672">...</span>$xs)))(<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=></span> $f(<span style="color:#a6e22e">fn</span>(<span style="color:#f92672">...</span>$xs) <span style="color:#f92672">=></span> $x($x)(<span style="color:#f92672">...</span>$xs))); -</span></span><span style="display:flex;"><span>$id <span style="color:#f92672">=</span> <span style="color:#a6e22e">\spl_object_id</span>(<span style="color:#f92672">...</span>); -</span></span><span style="display:flex;"><span>$put <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($c) <span style="color:#f92672">=></span> <span style="color:#a6e22e">\printf</span>(<span style="color:#e6db74">'%c'</span>, $c); -</span></span><span style="display:flex;"><span>$mm <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($p, $n) <span style="color:#f92672">=></span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">\ArrayObject</span>(<span style="color:#a6e22e">\array_fill</span>(<span style="color:#f92672">+!!</span>[], $n, $p)); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$👉 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> [<span style="color:#f92672">++</span>$mp, <span style="color:#f92672">++</span>$pc]; -</span></span><span style="display:flex;"><span>$👈 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> [<span style="color:#f92672">--</span>$mp, <span style="color:#f92672">++</span>$pc]; -</span></span><span style="display:flex;"><span>$👍 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> [$mp, <span style="color:#f92672">++</span>$pc, <span style="color:#f92672">++</span>$m[$mp]]; -</span></span><span style="display:flex;"><span>$👎 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> [$mp, <span style="color:#f92672">++</span>$pc, <span style="color:#f92672">--</span>$m[$mp]]; -</span></span><span style="display:flex;"><span>$📝 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> [$mp, <span style="color:#f92672">++</span>$pc, $put($m[$mp])]; -</span></span><span style="display:flex;"><span>$🤡 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> <span style="color:#a6e22e">match</span> ($m[$mp]) { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">=></span> [$mp, $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=></span> <span style="color:#a6e22e">fn</span>($pc, $n) <span style="color:#f92672">=></span> <span style="color:#a6e22e">match</span> ($id($p[$pc])) { -</span></span><span style="display:flex;"><span> $b <span style="color:#f92672">=></span> $loop(<span style="color:#f92672">++</span>$pc, <span style="color:#f92672">++</span>$n), -</span></span><span style="display:flex;"><span> $e <span style="color:#f92672">=></span> $n <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">?</span> <span style="color:#f92672">++</span>$pc <span style="color:#f92672">:</span> $loop(<span style="color:#f92672">++</span>$pc, <span style="color:#f92672">--</span>$n), -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=></span> $loop(<span style="color:#f92672">++</span>$pc, $n), -</span></span><span style="display:flex;"><span> })($pc, <span style="color:#f92672">-!</span>[])], -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=></span> [$mp, <span style="color:#f92672">++</span>$pc], -</span></span><span style="display:flex;"><span>}; -</span></span><span style="display:flex;"><span>$🎪 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> <span style="color:#a6e22e">match</span> ($m[$mp]) { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">=></span> [$mp, <span style="color:#f92672">++</span>$pc], -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=></span> [$mp, $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=></span> <span style="color:#a6e22e">fn</span>($pc, $n) <span style="color:#f92672">=></span> <span style="color:#a6e22e">match</span> ($id($p[$pc])) { -</span></span><span style="display:flex;"><span> $e <span style="color:#f92672">=></span> $loop(<span style="color:#f92672">--</span>$pc, <span style="color:#f92672">++</span>$n), -</span></span><span style="display:flex;"><span> $b <span style="color:#f92672">=></span> $n <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">?</span> $pc<span style="color:#f92672">+!</span>[] <span style="color:#f92672">:</span> $loop(<span style="color:#f92672">--</span>$pc, <span style="color:#f92672">--</span>$n), -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=></span> $loop(<span style="color:#f92672">--</span>$pc, $n), -</span></span><span style="display:flex;"><span> })($pc, <span style="color:#f92672">-!</span>[])], -</span></span><span style="display:flex;"><span>}; -</span></span><span style="display:flex;"><span>$🐘 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($p) <span style="color:#f92672">=></span> $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=></span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">isset</span>($p[$pc]) <span style="color:#f92672">&&</span> $loop($m, $p, $b, $e, <span style="color:#f92672">...</span>($p[$pc]($m, $p, $b, $e, $mp, $pc))) -</span></span><span style="display:flex;"><span>)($mm(<span style="color:#f92672">+!!</span>[], <span style="color:#f92672">+</span>(<span style="color:#f92672">!</span>[]<span style="color:#f92672">.!</span>[])), $p, $id($🤡), $id($🎪), <span style="color:#f92672">+!!</span>[], <span style="color:#f92672">+!!</span>[]); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$🐘([ -</span></span><span style="display:flex;"><span> $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, -</span></span><span style="display:flex;"><span> $🤡, -</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, -</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, -</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, -</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, -</span></span><span style="display:flex;"><span> $👈, $👈, $👈, $👈, $👎, -</span></span><span style="display:flex;"><span> $🎪, -</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $📝, -</span></span><span style="display:flex;"><span> $👎, $👎, $📝, -</span></span><span style="display:flex;"><span> $👉, $👎, $👎, $👎, $📝, -</span></span><span style="display:flex;"><span> $👉, $👎, $👎, $👎, $📝, -</span></span><span style="display:flex;"><span> $👎, $👎, $📝, -</span></span><span style="display:flex;"><span> $👎, $📝, -</span></span><span style="display:flex;"><span> $👈, $📝, -</span></span><span style="display:flex;"><span> $👉, $👉, $👎, $👎, $📝, -</span></span><span style="display:flex;"><span> $👍, $👍, $👍, $👍, $👍, $👍, $👍, $📝, -</span></span><span style="display:flex;"><span> $👈, $👎, $👎, $👎, $👎, $📝, -</span></span><span style="display:flex;"><span> $👈, $📝, -</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $📝, -</span></span><span style="display:flex;"><span> $👉, $👎, $📝, -</span></span><span style="display:flex;"><span> $👈, $📝, -</span></span><span style="display:flex;"><span>]); -</span></span></code></pre></div><p>この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。</p> -<h2 id="解説">解説</h2> -<h3 id="絵文字">絵文字</h3> -<p>まず目につくのは大量の絵文字だろう。 -PHP は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。</p> -<h3 id="プログラム全体">プログラム全体</h3> -<p>Brainf*ck のインタプリタとプログラムになっている。 -Brainf*ck とは、難解プログラミング言語のひとつであり、ここで説明するよりも Wikipedia の該当ページを読んだ方がよい。</p> -<p><a href="https://ja.wikipedia.org/wiki/Brainfuck">https://ja.wikipedia.org/wiki/Brainfuck</a></p> -<p>なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。</p> -<pre tabindex="0"><code>+ + + + + + + + + + -[ - > + + + - > + + + + + - > + + + + + + + + + + + + - > + + + + + + + + + + - < < < < - -] -> + + + + + . -- - . -> - - - . -> - - - . -- - . -- . -< . -> > - - . -+ + + + + + + . -< - - - - . -< . -> + + . -> - . -< . -</code></pre><p>実行結果はこちら: <a href="https://ideone.com/22VWmb">https://ideone.com/22VWmb</a></p> -<p>それぞれの絵文字で表された関数が、各命令に対応している。</p> -<ul> -<li><code>$👉</code>: <code>></code></li> -<li><code>$👈</code>: <code><</code></li> -<li><code>$👍</code>: <code>+</code></li> -<li><code>$👎</code>: <code>-</code></li> -<li><code>$📝</code>: <code>.</code></li> -<li><code>$🤡</code>: <code>[</code></li> -<li><code>$🎪</code>: <code>]</code></li> -</ul> -<p><code>,</code> (入力) に対応する関数はない (このプログラムでは使わないので用意していない)。</p> -<p>なお、<code>$🐘</code> はいわゆる main 関数であり、プログラムの実行部分である。</p> -<h3 id="絵文字の選択">絵文字の選択</h3> -<p>おおよそ意味に合致するよう選んでいるが、<code>$🤡</code> と <code>$🎪</code> は弊社デジタルサーカスにちなんでいる。 -また、<code>$🐘</code> は PHP のマスコットの象に由来する。</p> -<h3 id="strict_types">strict_types</h3> -<p><code>declare</code> 文の <code>strict_types</code> に指定できるのは、<code>0</code> か <code>1</code> の数値リテラルだが、 -<code>0x0</code> や <code>0b1</code> のような値も受け付ける。 -今回は、PHP 8.1 から追加された、<code>0O</code> または <code>0o</code> から始まる八進数リテラルを使った。</p> -<h3 id="url">URL</h3> -<p>ソースコードのライセンスを示したこの部分だが、</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">https</span><span style="color:#f92672">://</span><span style="color:#a6e22e">creativecommons</span><span style="color:#f92672">.</span><span style="color:#a6e22e">org</span><span style="color:#f92672">/</span><span style="color:#a6e22e">publicdomain</span><span style="color:#f92672">/</span><span style="color:#a6e22e">zero</span><span style="color:#f92672">/</span><span style="color:#ae81ff">1.0</span><span style="color:#f92672">/</span> -</span></span></code></pre></div><p>完全に合法な PHP のコードである。 -<code>https:</code> 部分はラベル、<code>//</code> 以降は行コメントになっている。</p> -<h3 id="リテラルなしで数値を生成する">リテラルなしで数値を生成する</h3> -<p>ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。 -PHP では、型変換を利用することで任意の整数を作り出すことができる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[]); -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">1</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+!</span>[]); -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">2</span> <span style="color:#f92672">===</span> <span style="color:#f92672">!</span>[]<span style="color:#f92672">+!</span>[]); -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">3</span> <span style="color:#f92672">===</span> <span style="color:#f92672">!</span>[]<span style="color:#f92672">+!</span>[]<span style="color:#f92672">+!</span>[]); -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">10</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+</span>(<span style="color:#f92672">!</span>[]<span style="color:#f92672">.+!!</span>[])); -</span></span></code></pre></div><p><code>[]</code> に <code>!</code> を適用すると <code>true</code> が返ってくる。それに <code>+</code> -を適用すると、<code>bool</code> から <code>int</code> ヘの型変換が走り、<code>1</code> が生成される。<code>10</code> -はさらにトリッキーだ。まず <code>1</code> と <code>0</code> を作り、<code>.</code> で文字列として結合する -(<code>'10'</code>)。これに <code>+</code> を適用すると、<code>string</code> から <code>int</code> -への型変換が走り、<code>10</code> が生まれる (コード量に頓着しないなら、<code>1</code> を 10 -個足し合わせてももちろん 10 が作れる)。</p> -<p>また、<code>error_reporting</code> に指定しているのは <code>-1</code> である。 -これは、<code>!</code> によって文字列を <code>false</code> にし、<code>+</code> によって <code>false</code> を <code>0</code> にし、さらにビット反転して <code>-1</code> にしている。</p> -<h3 id="if-文なしで条件分岐"><code>if</code> 文なしで条件分岐</h3> -<p>三項演算子ないし <code>match</code> 式を使うことで、<code>if</code> を一切書かずに条件分岐ができる。 -また、<code>&&</code> / <code>||</code> も使えることがある。 -遅延評価が不要なケースでは、<code>[$t, $f][$cond]</code> のような形で分岐することもできる。</p> -<h3 id="whilefor-文なしでループ"><code>while</code>、<code>for</code> 文なしでループ</h3> -<p>不動点コンビネータを使って無名再帰する (詳しい説明は省略する。これらの単語で検索してほしい)。 -ここでは、一般に Z コンビネータとして知られるものを使った (<code>$z</code>)。</p> -<p>実際のところ、<code>$🤡</code> や <code>$🎪</code>、<code>$🐘</code> は、一度 Scheme (Lisp の一種) で書いてから PHP に翻訳する形で記述した。</p> -<p>なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) ので、 -あまりに長い brainf*ck プログラムを書くとスタックオーバーフローする。</p> -<h1 id="第2問-riddlephp">第2問 riddle.php</h1> -<p>ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#e6db74">/********************************************************* -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * This program displays a PHPer token. * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Guess 'N'. * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Hints: * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - N itself has no special meaning, e.g., 42, 8128, * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * it is selected at random. * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - Each element of $token represents a single letter. * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - One letter consists of 5x5 cells. * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - Remember, the output is a complete PHPer token. * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * License: * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * https://creativecommons.org/publicdomain/zero/1.0/ * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> *********************************************************/</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">N</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> <span style="color:#75715e">/* Change it to your answer. */</span>; -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672"><=</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&&</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672"><=</span> <span style="color:#ae81ff">0</span><span style="color:#a6e22e">b11111_11111_11111_11111_11111</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$token <span style="color:#f92672">=</span> [ -</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x14B499C</span>, -</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x0BE34CC</span>, <span style="color:#ae81ff">0x01C9C69</span>, -</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x0ECA069</span>, <span style="color:#ae81ff">0x01C2449</span>, <span style="color:#ae81ff">0x0FDB166</span>, <span style="color:#ae81ff">0x01C9C69</span>, -</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x01C1C66</span>, <span style="color:#ae81ff">0x0FC1C47</span>, <span style="color:#ae81ff">0x01C1C66</span>, -</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x10C5858</span>, <span style="color:#ae81ff">0x1E4E3B8</span>, <span style="color:#ae81ff">0x1A2F2F8</span>, -</span></span><span style="display:flex;"><span>]; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($token <span style="color:#66d9ef">as</span> $x) { -</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">'%025b'</span>, $x); -</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">'0'</span>, <span style="color:#e6db74">'1'</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">' '</span>, <span style="color:#e6db74">'#'</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x); -</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>)); -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">"</span><span style="color:#e6db74">{</span>$x<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n\n</span><span style="color:#e6db74">"</span>; -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。 -トークンを得るためには、ソースコードを読み、定数 <code>N</code> を特定する必要がある。</p> -<p>ここでは、私の想定解を解説する。</p> -<h2 id="読解">読解</h2> -<p>まずはソースコードを読んでいく。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$token <span style="color:#f92672">=</span> [ -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 略 -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>]; -</span></span></code></pre></div><p>数値からなる <code>$token</code> があり、各要素をループしている。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>; -</span></span></code></pre></div><p>まずは排他的論理和 (xor) を取り、</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">'%025b'</span>, $x); -</span></span></code></pre></div><p>二進数に変換して、</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">'0'</span>, <span style="color:#e6db74">'1'</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">' '</span>, <span style="color:#e6db74">'#'</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x); -</span></span></code></pre></div><p>0 を空白に、1 を <code>#</code> にし、</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>)); -</span></span></code></pre></div><p>5文字ごとに区切ったあと、改行で結合している。</p> -<h2 id="ヒント">ヒント</h2> -<p>次に、ソースコードに書いてあるヒントを読んでいく。</p> -<ul> -<li><code>N</code> それ自体は、42 や 8128 といったような特別な意味を持たず、ランダムに決められている</li> -<li><code>$token</code> の各要素は、1文字を表す</li> -<li>1文字は 5x5 のセルからなる</li> -<li>出力されるのは、完全な PHPer トークンである</li> -</ul> -<p>ここで、PHPer トークンは必ず <code>#</code> 記号から始まることを思いだすと、 -<code>$token</code> の最初の数字 <code>0x14B499C</code> は、変換の結果 <code>#</code> になるのではないかと予想される (なお、このことは、リポジトリの README ファイルに追加ヒントとして書かれている)。</p> -<h2 id="解く">解く</h2> -<p>ここまでわかれば、あと一歩で解ける。すなわち、<code>0x14B499C</code> が <code>#</code> に変換されるような <code>N</code> を見つければよい。</p> -<p><code>N</code> は高々</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672"><=</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&&</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672"><=</span> <span style="color:#ae81ff">0</span><span style="color:#a6e22e">b11111_11111_11111_11111_11111</span>); -</span></span></code></pre></div><p>なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0x14B499C</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">'%025b'</span>, $x); -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">'0'</span>, <span style="color:#e6db74">'1'</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">' '</span>, <span style="color:#e6db74">'#'</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x); -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>)); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>($x <span style="color:#f92672">===</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">" # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">" # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">" # # "</span>); -</span></span></code></pre></div><p>この一連の変換に対する逆変換を考えると、次のようになる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">" # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">" # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">" # # "</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">''</span>, <span style="color:#a6e22e">explode</span>(<span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>, $x)); -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">' '</span>, <span style="color:#e6db74">'#'</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">'0'</span>, <span style="color:#e6db74">'1'</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x); -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">bindec</span>($x); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$n <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#ae81ff">0x14B499C</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">"N = </span><span style="color:#e6db74">$n\n</span><span style="color:#e6db74">"</span>; -</span></span></code></pre></div><p>これを実行すると、<code>N</code> が得られる。</p> -<h1 id="第3問-toquinephp">第3問 toquine.php</h1> -<p>ソースコードはこちら。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">// License: https://creativecommons.org/publicdomain/zero/1.0/ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// This is a quine-like program to generate a PHPer token. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// Execute it like this: php toquine.php | php | php | php | ... -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> -</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#e6db74"><<<'</span><span style="color:#e6db74">Q</span><span style="color:#e6db74">' -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"><?cuc -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Yvprafr: uggcf://perngvirpbzzbaf.bet/choyvpqbznva/mreb/1.0/ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Guvf vf n dhvar-yvxr cebtenz gb trarengr n CUCre gbxra. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Rkrphgr vg yvxr guvf: cuc gbdhvar.cuc | cuc | cuc | cuc | ... -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%f$f = %f; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$f = fge_ebg13($f); $kf = [ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%f, -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">]; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$g = ahyy.snyfr; sbe ($v = 0; $v <= vagqvi(__YVAR__-035,6); ++$v) vs (!vffrg($kf[$v])) oernx; ryfr -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$g .= vzcybqr("\a", fge_fcyvg(fge_ercynpr(['0','1'], [' ','##'], fcevags(pue(37) . '025o', $kf[$v])), 012)) . "\a\a"; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$jf = neenl_znc(sa($j) => vzcybqr(', ', $j), neenl_puhax(neenl_znc(sa($k) => fcevags('0k' . pue(37) . '07K', $k), $kf), 10)); -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">cevags($f, $g, fge_ebg13("<<<'Q'\a{$f}\aQ"), vzcybqr(",\a", $jf)); -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span><span style="color:#e6db74">Q</span>; -</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_rot13</span>($s); $xs <span style="color:#f92672">=</span> [ -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x0AFABEA</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F2109F</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x0002800</span>, <span style="color:#ae81ff">0x1F2109F</span>, <span style="color:#ae81ff">0x0117041</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1F295B7</span>, -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x010FC21</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1151151</span>, <span style="color:#ae81ff">0x010FC21</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F295B7</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F295B7</span>, <span style="color:#ae81ff">0x1F8C63F</span>, -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x1F8C631</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x17AD6BD</span>, <span style="color:#ae81ff">0x17AD6BD</span>, <span style="color:#ae81ff">0x1F8C63F</span>, <span style="color:#ae81ff">0x1F295B7</span>, -</span></span><span style="display:flex;"><span>]; -</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">.</span><span style="color:#66d9ef">false</span>; <span style="color:#66d9ef">for</span> ($i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; $i <span style="color:#f92672"><=</span> <span style="color:#a6e22e">intdiv</span>(<span style="color:#66d9ef">__LINE__</span><span style="color:#f92672">-</span><span style="color:#ae81ff">035</span>,<span style="color:#ae81ff">6</span>); <span style="color:#f92672">++</span>$i) <span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">isset</span>($xs[$i])) <span style="color:#66d9ef">break</span>; <span style="color:#66d9ef">else</span> -</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">.=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>, <span style="color:#a6e22e">str_split</span>(<span style="color:#a6e22e">str_replace</span>([<span style="color:#e6db74">'0'</span>,<span style="color:#e6db74">'1'</span>], [<span style="color:#e6db74">' '</span>,<span style="color:#e6db74">'##'</span>], <span style="color:#a6e22e">sprintf</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#ae81ff">37</span>) <span style="color:#f92672">.</span> <span style="color:#e6db74">'025b'</span>, $xs[$i])), <span style="color:#ae81ff">012</span>)) <span style="color:#f92672">.</span> <span style="color:#e6db74">"</span><span style="color:#ae81ff">\n\n</span><span style="color:#e6db74">"</span>; -</span></span><span style="display:flex;"><span>$ws <span style="color:#f92672">=</span> <span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">fn</span>($w) <span style="color:#f92672">=></span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">', '</span>, $w), <span style="color:#a6e22e">array_chunk</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=></span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">'0x'</span> <span style="color:#f92672">.</span> <span style="color:#a6e22e">chr</span>(<span style="color:#ae81ff">37</span>) <span style="color:#f92672">.</span> <span style="color:#e6db74">'07X'</span>, $x), $xs), <span style="color:#ae81ff">10</span>)); -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">printf</span>($s, $t, <span style="color:#a6e22e">str_rot13</span>(<span style="color:#e6db74">"<<<'D'</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">{</span>$s<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">D"</span>), <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">",</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>, $ws)); -</span></span></code></pre></div><p>コメントにもあるとおり、次のようにして実行すれば答えがでてくる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php toquine.php | php | php | php | ... -</span></span></code></pre></div><p>実際にはもう少しパイプで繋げなければならない。</p> -<h2 id="解説-1">解説</h2> -<h3 id="プログラム全体-1">プログラム全体</h3> -<p>コメントにもあるとおり、これは quine (風) のプログラムになっている。 -Quine とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。</p> -<p>このプログラムは、実行すると自身とほとんど同じプログラムを出力する。 -異なるのはトークンになっている部分のみである。</p> -<h3 id="トークン">トークン</h3> -<p><code>$xs</code> がトークンに対応している。変換のロジックは <code>riddle.php</code> とほぼ同じなので省略する。</p> -<h3 id="状態保持">状態保持</h3> -<p>トークンの何文字目まで出力したかを、ソースコードを変えずに (quine なので) 覚えておく必要がある。 -このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、<code>__LINE__</code> から情報を取得している。</p> -<h3 id="rot-13">ROT 13</h3> -<p>Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。 -これがあまり美しくないので、<code>toquine.php</code> では、ROT 13 変換を使って難読化した。</p> -<p>それにしてもなぜこんなものが標準ライブラリに……。</p> -<h1 id="おわりに">おわりに</h1> -<p>解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。</p> -<p>今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、 -来年は 5問、より面白い問題を持っていきます。</p> -<p>実はもう作りはじめているので、どうか来年もありますように……。</p> -]]></description> - </item> - - <item> - <title>PHPerKaigi 2021</title> - <link>https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/</link> - <pubDate>Tue, 30 Mar 2021 23:22:40 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/</guid> - <description><![CDATA[ <h1 id="phperkaigi-2021-参加レポ">PHPerKaigi 2021 参加レポ</h1> -<p>2021-03-26 から 2021-03-28 にかけて開催された、<a href="https://phperkaigi.jp/2021/">PHPerKaigi 2021</a> に一般参加者として参加した。 -弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> (今年1月から勤務) はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p> -<p>このようなカンファレンスには初めて参加するのでかねてより心待ちにしていたのだが、生憎2日目から体調を崩してしまい、この記事も途中までとなっている。まだ見ていないセッションも多いが、ひとまず現時点での参加レポを書いておく。</p> -<p>発表はトラック A、B に分かれていたのだが、今回はすべて A トラックを視聴している (切り替えるのが面倒だっただけ)。</p> -<h2 id="凡例">凡例</h2> -<blockquote> -<p>発表・スライドのメモ (引用ではない)</p> -</blockquote> -<p>感想など</p> -<h2 id="day-0-前夜祭-20210327">Day 0 前夜祭 (2021/03/27)</h2> -<h3 id="1730-a">17:30 [A]</h3> -<p>PHP で AWS Lambda</p> -<blockquote> -<p>Rails のプロジェクトを PHPer のメンバのみでメンテ -→他のメンバもわかる PHP にリプレースを検討</p> -<p>サーバレス</p> -<ul> -<li>サーバ・インフラの管理が不要</li> -<li>アプリケーションコードの知識だけで保守可能</li> -</ul> -<p>ゼロベースで作れる案件が (Railsの件とは別に) あるため、そちらで試験的に導入?</p> -<p>AWSの学習 -AWS のドキュメント -DevelopersIO</p> -<p>AWS Lambda のカスタムランタイムで PHP を動かす</p> -<p>サーバのセットアップや維持管理を気にしなくて良い -サーバーレスで PHP を動かすツールがすでにある -サーバーレス構築はすんなり</p> -<p>今は Laravel がルーティングしている -Laravel Livewire を Lambda に載せられないか? -デプロイ方法は? -バッチ処理は? (Lambda は 15分の制限)</p> -<p>Lambda でコンテナイメージがサポートされるように</p> -<p>抽象化されたもの「だけ」しか知らないよりも具象の理解は助けになる</p> -</blockquote> -<p>AWS Lambda のような Function as a Service はマイクロサービス化における一つの到達点に思えるのだが、これを使って実際に web サービスを作る具体的なイメージがまだ見えない (注: すべて for me として書いている)。</p> -<p>PHP on AWS Lambda があれだけ簡単に動かせるのには驚いた。</p> -<p>勝手に AWS Lambda だとフットプリントの軽さが求められそう (= PHP + Laravel などでは動かなさそう) だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。</p> -<h3 id="1810-a">18:10 [A]</h3> -<p>大規模サイトの SEO</p> -<blockquote> -<p>大規模サイト (100万ページ以上) -Google の基準</p> -<p>クロールバジェットを意識したSEO</p> -<p>大規模サイトでコンテンツが中頻度 (1回/週) で更新 OR 中規模サイト (10,000以上) でコンテンツが目まぐるしく変更される -これを満たさないなら、クロールバジェットを考えなくてもいい</p> -<p>サーチコンソール -「カバレッジ」の「除外」 -多すぎるのは問題→クロールバジェットを浪費している</p> -<ul> -<li>クエリの順番を決める</li> -<li>空の値のルールを決めておく</li> -<li>リダイレクトすればインデックスはうまくいく</li> -<li>リンクが存在する限りクロールはされる</li> -</ul> -<p>リニューアル前のURL</p> -<p>インデックスは移行される -リンクのURLが存在する限り、別のURLとしてクロールされる -リダイレクトされるとはいえ、リニューアル前のURLは移行した方が良い -リニューアルで無視されるようになったパラメータも注意</p> -<p>robotes.txt で拒否しているのにクロールされる -一時的に拒否を外して 404 や 301 を読ませる -内部リンクを確認する -JS でのリンクに書き換え</p> -<p>クエリパラメータからURLのパスに -<code>/tokyo?area=HOGE</code> → <code>/tokyo/HOGE</code></p> -<p>URL 設計だいじ</p> -</blockquote> -<p>SEO (Search Engine Optimization) は大して知らないので新鮮な話が多かった。その分語れることも少ない……。</p> -<h3 id="1850-a">18:50 [A]</h3> -<blockquote> -<p>知覚可能 -操作可能 -理解可能 -堅牢 ちゃんとしたHTMLを書く (閉じタグ・入れ子構造など)</p> -<ul> -<li> -<p>標準の HTML を適切に使う</p> -</li> -<li> -<p>WAI-ARIA</p> -</li> -<li> -<p>キーボードフレンドリー</p> -</li> -<li> -<p>マシンフレンドリー</p> -</li> -<li> -<p>SEOフレンドリー</p> -</li> -</ul> -<p>button タグ -→キーボード -h1 タグ -→スクリーンリーダー・クローラ -a タグ</p> -<p>WAI-ARIA -HTML では表現できないセマンティクスを追加する</p> -<ul> -<li>ロール -<ul> -<li>何をするのか?</li> -<li>ユーザーアクションによって変化しない</li> -</ul> -</li> -<li>プロパティ -<ul> -<li>関連づけられたデータ</li> -</ul> -</li> -<li>ステート -<ul> -<li>現在の状態</li> -</ul> -</li> -</ul> -<p>まずは標準の HTML 要素で解決する -何でもかんでも WAI-ARIA を使えばいいというものではない</p> -<p>マウスホバーでツールチップが出てくるが、キーボード操作では出てこない</p> -<p>VoiceOver</p> -<p>全ての属性を使う必要はない -あくまでアクセシビリティを上げるための方法の一つにすぎない</p> -</blockquote> -<p>つい最近 WAI-ARIA についての記事を読んだばかりだったので個人的にタイムリーな話題だった。(あまりこの言葉を使いたくないのだが) いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。</p> -<h3 id="1930-a">19:30 [A]</h3> -<p>PHP で FUSE</p> -<p>個人的に楽しみだった発表。</p> -<blockquote> -<p>VFS (virtual filesystem) vs 具体的なファイルシステム</p> -<p>最適な実装方法は状況により異なる</p> -<p>アプリケーションに見せるAPIは変えずに実装を隠蔽する→VFS</p> -<p>カーネルのプログラムを作るのは難しい</p> -<ul> -<li>権限がデカすぎる</li> -<li>システム全体がクラッシュ</li> -<li>セキュリティリスク</li> -<li>開発サイクルを回しづらい</li> -<li>ネイティブコードにコンパイルされる言語である必要がある</li> -</ul> -<p>Filesystem in USEr space (FUSE)</p> -<ul> -<li>特定の C の関数を呼ぶことで filesystem が作れる</li> -<li>FFI を持つ言語なら FUSE が使える</li> -</ul> -<p>SSHFS / s3fs / Docker Desktop</p> -<p>Linux 以外でも使える</p> -<ul> -<li>dokany (on Windows)</li> -<li>osxfuse</li> -</ul> -<p>VFS: システムコールが呼ばれると、ファイルシステムによってコール -FUSE: カーネル空間からユーザ空間へ通信</p> -<p>高レベルなラッパで型をつける</p> -<p>PHP 以外では Wordpress を FUSE にマウントする実装がある (C, Python など)</p> -<ul> -<li>grep できる</li> -<li>sed できる</li> -<li>編集できる</li> -</ul> -</blockquote> -<p>期待通りの興味深い発表だった。FUSE 自体も今回の発表で知ったのだが、これ本体の実装を見るのも面白そうだ。 -この発表を聞きながらファイルシステムにマウントできそうなものを考えていたのだが、およそ木構造をしているものすべてと言えそうだ (ハンマーしか持っていないと云々)。何かできそうだがなかなか思いつかない。</p> -<h2 id="day-1-20210327">Day 1 (2021/03/27)</h2> -<h3 id="1050-a">10:50 [A]</h3> -<p>ATDD</p> -<blockquote> -<ul> -<li>ユーザーストーリー</li> -<li>ユニットテスト</li> -<li>CI/CD</li> -</ul> -<p>ユーザストーリーの受け入れ条件が曖昧になりがち -デグレチェックがユニットレベルでは収まらない場合、手動で同じシナリオをテストしている</p> -<p>Q2の強化 -アジャイルテストの4象限</p> -<p>技術面/ビジネス面 -開発チーム支援(コーディング前・コーディング中)/製品批評(コーディング後)</p> -<ul> -<li>Q1: 技術面 & チーム支援 -<ul> -<li>TDD</li> -<li>ユニットテストなど</li> -</ul> -</li> -<li>Q2: ビジネス面 & チーム支援 -<ul> -<li>ATDD</li> -<li>ビジネス面の受け入れテストで駆動する</li> -</ul> -</li> -</ul> -<p>Agile Alliance -ユーザストーリーのスキルレベルを高める</p> -<p>テストピラミッド</p> -<ul> -<li> -<p>UI Tests</p> -</li> -<li> -<p>Service Tests</p> -</li> -<li> -<p>Unit Tests</p> -</li> -<li> -<p>異なる粒度のテストを書く</p> -</li> -<li> -<p>高レベルになるほど、持つべきテストは少なくなる</p> -<ul> -<li>ピラミッド型になる</li> -</ul> -</li> -</ul> -<p>高レベルテストが多すぎる→アイスクリームコーン アンチパターン</p> -<p>ATDD (Acceptance TDD) -API経由・UI経由での高レベルテスト E2E test</p> -<p>ストーリ受け入れテスト</p> -<p>入れ子のフィードバックループ -ATDD(外側) と TDD(内側)</p> -<p>外部品質・内部品質</p> -<p>バーティカルスライスのデリバリー</p> -<ul> -<li>cucumber</li> -<li>gauge</li> -<li>behat</li> -</ul> -<p>ユビキタス言語 -手動テストもspecに書く -自動化は可能だがコスパが悪い -失敗することがわかっているテスト(レッドテスト)はCIから外す -失敗時の原因究明が難しい -饒舌なエラーメッセージ -状況のスナップショット</p> -<p>Continuous Testing</p> -</blockquote> -<p>User Acceptance Test (UAT) くらいの規模になると個人開発・趣味開発では触れない領域なので、大いに勉強になった。スライドに添付されている資料が相当に充実していたので、これを読むのが本番といった様相すら感じる。 -高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。</p> -<h3 id="1150-a">11:50 [A]</h3> -<p>型解析を用いたリファクタリング</p> -<p>型のある世界で生きてきた身として大いに楽しみにしていた発表。</p> -<blockquote> -<ul> -<li>PHPStan</li> -<li>Phan</li> -<li>Psalm</li> -</ul> -<p>autoload も認識できる -bootstrapFiles</p> -<p>編集箇所と利用箇所を CI でチェック -ルールレベルを徐々に引き上げていく -警告が多すぎると見落としてしまう・無視されやすくなる</p> -<p>型がついていないことによるエラーが多い</p> -<p>型よりも詳細な検査 <code>Util_Assert::min</code></p> -<p>SQL を静的解析 -placeholder の型付け</p> -<p>警告レベルを低いレベルから導入 -タイプヒントを積極的に書いていく -PHPStan の拡張を追加する</p> -</blockquote> -<p>昨今、動的型付き言語での型宣言・型アノテーション・型ヒントの導入が相次いでいる。長らく静的型付き言語を書いてきた私からすると、ようやく気づいたかといったところだが、ともかく型を導入する言語が増えてきた。 -今のプロジェクトでも新しく追加するコードには型をつけるよう努めているが、どうしても古いコードには型がついていない。個人的には型のないコードに対してどう型を自動的に付けるかという点に興味があり、その点で Ruby の typeprof には注目している。</p> -<h3 id="1230-a">12:30 [A]</h3> -<p>昼食をとっていた。事前に何か食料を買っておくべきだった。</p> -<h3 id="1310-a">13:10 [A]</h3> -<p>Documentation as Code</p> -<p>この発表も以前から非常に楽しみにしていた。</p> -<blockquote> -<p>開発開始までのオーバーヘッド -新規にチームにジョイン -担当範囲外の機能を理解 -オンボーディングのコスト</p> -<p>PHPerKaigi 2020 で発表あり</p> -<p>継続的にシステムの理解を助けるドキュメント</p> -<p>継続的ドキュメンテーション -システムとドキュメントの乖離</p> -<p>書いてあることが間違っている・足りない</p> -<ul> -<li>徐々にずれていく</li> -<li>システムの更新タイミングとドキュメントの更新タイミングに差がある</li> -</ul> -<p>システムとドキュメントは対応関係がある</p> -<ul> -<li>間違ったドキュメント</li> -<li>存在しないドキュメント</li> -</ul> -<p>システムとドキュメントの乖離を定量化する -継続的に -システムの更新に近いタイミングで ドキュメントを更新し続ける</p> -<p>Documentation as Code</p> -<p>コードと同じツールでドキュメントを書く</p> -<ul> -<li>issue tracker</li> -<li>vcs</li> -<li>plain text markup</li> -<li>automation</li> -</ul> -<p>開発者 -システム -ドキュメント -構造化データ -ソフトウェア</p> -<p>システムから構造化データを抽出する -PHPDoc -OpenAPI</p> -<p>ビュー 関心ごとに合わせてアーキテクチャを一つ以上の側面(断面)で説明する</p> -<p>ビューの単位でドキュメントに</p> -<p>スタックトレースからのドキュメント生成</p> -</blockquote> -<p>ドキュメントの管理は現プロジェクトでも課題と感じている。作られた当初は正しくても、実態と乖離していくのを止めるのは困難を極める。全体的に興味深い発表だったが、特にスタックトレースからのドキュメント生成というアイデアに惹かれるものを感じた。スタックトレースという実態と不可分な (乖離しない) 情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。</p> -<h3 id="1410-a">14:10 [A]</h3> -<p>cookie による session 管理</p> -<p>全体的に基本的な話だったので特に触れない。Cookie やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。</p> -<h3 id="1450-a">14:50 [A]</h3> -<p>PHP のエラーと例外</p> -<blockquote> -<p>エラー PHPエンジンがエラーを通知する -例外 プログラムが投げる</p> -<p>PHP7-8とエラー</p> -<p>PHPエンジンのエラーの一部が \Error に変換されるようになった -→ try-catch で捕捉できる</p> -<p>\Error は例外とは異なる</p> -<p>PHP8 でエラーレベルの引き上げ</p> -<ul> -<li>捕捉すべきもの -<ul> -<li>recoverable</li> -</ul> -</li> -<li>捕捉すべきでないもの -<ul> -<li>unrecoverable</li> -<li>開発時に対処できるもの</li> -</ul> -</li> -</ul> -<p>例外</p> -<ul> -<li>捕捉して事後処理</li> -<li>捕捉せず(or 捕捉した上で)さらに上に是非を問う</li> -</ul> -<p>開発段階で例外を把握し、ハンドリングを考えておく</p> -<p>\Throwable \Exception と \Error</p> -<p>\Error はキャッチすべきでない</p> -<ul> -<li> -<p>\Error</p> -<ul> -<li>本番で起きてはいけない</li> -</ul> -</li> -<li> -<p>\LogicException</p> -<ul> -<li>本番で起きてはいけない -→生じないのだから捕捉もしない</li> -</ul> -</li> -<li> -<p>\RuntimeException</p> -<ul> -<li>起こるかもしれないので本番環境でも考慮する</li> -</ul> -</li> -</ul> -<p>捕捉して対応するのではなく、未然に防ぐ</p> -<p>独自例外を使う -\Exception を投げてしまうと、 -catch (\Exception)せざるを得ない -→catch 範囲が広すぎる</p> -<p>SPL の例外を使う</p> -<p>例外翻訳 -上位のレイヤが下位のレイヤの例外を捕捉し、上位レイヤのAPIに「翻訳」する -下位レイヤの知識に依存させない</p> -<p>@throws -捕捉してほしい例外を書き連ねておく</p> -<p>呼び出しもとに負わせたい責任</p> -</blockquote> -<p>PHP を学んでいる途中の私としては、今まさに聞きたい発表だった (現時点で PHP を書き始めてから 4ヶ月ほどになる)。</p> -<p>個人的に例外やエラーを最もうまく扱っているのは Go、Swift、Rust、Haskell などのエラーを「値として」扱う言語だと思っている。try-catch は通常の処理フローを完全に壊してしまう上、構文としても重すぎる。値としてのエラー通知は C言語時代への回帰ともいえるが、その頃と異なるのはエラーを暗黙のうちに握り潰すことがないということだ。これらの言語は型を持っており、静的に検証ができる (C のそれはまともな型付けではない。念のため)。</p> -<p>PHP のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。</p> -<h3 id="1530-a">15:30 [A]</h3> -<p>Laravel のメール認証</p> -<p>Laravel の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。</p> -<h3 id="1610-a">16:10 [A]</h3> -<p>gRPC</p> -<blockquote> -<p>Unary RPCs -Server streaming RPCs -Client streaming RPCs -Bidirectional streaming RPCs</p> -<p>Protobuf</p> -<p>実装とAPIが乖離しにくい -自動生成 -複数言語でも相互に使える</p> -<p>マイクロサービスのサービス通信 -スマホアプリ -ゲームサーバ</p> -<p>PHP では?</p> -<p>PHP ではストリーミングが難しい -リクエストごとにプロセスが使い捨て</p> -<p>PHP ではgRPCのクライアントしか対応していない</p> -<p>gRPC-Web -ブラウザで扱うためのJSライブラリ+プロトコル</p> -<p>HTTP/1.1 でも使える -Unary RPC と Server streaming RPC のみ</p> -<p>Envoy -Nginx などで相互に gRPC と gRPC-Web で変換</p> -<p>Amp -イベント駆動な並行処理のフレームワーク</p> -<p>HTTP/2 対応</p> -<p>C#のgRPC-Webが楽</p> -</blockquote> -<p>(発表の中でもまさに同じことをおっしゃっていたが) PHP 以外の方が向いているだろう、というのが第一の感想である。gRPC はそれ自体というよりも Protobuf というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。</p> -<h3 id="1650-a">16:50 [A]</h3> -<p>アーキテクチャテスト</p> -<blockquote> -<p>Independent Core Layer Pattern</p> -<p>開発初期のアーキテクチャが崩れる -アーキテクチャ観点のコードレビューができない</p> -<p>どこにクラスを置けばよいか? -ドキュメントがない</p> -<p>アーキテクチャ設計に関する知識が属人化・暗黙知化</p> -<p>ガイドライン</p> -<ul> -<li>最初にルールを決めるのは簡単</li> -<li>ルール通り作り始めるのも簡単 -<ul> -<li>→維持するのが難しい、人が決めたものゆえ壊れやすい</li> -</ul> -</li> -</ul> -<p>PHP の特性</p> -<ul> -<li>クラスは public</li> -<li>可視性の制御が public / protected / private のみ</li> -<li>依存関係の制御が困難</li> -</ul> -<p>アーキテクチャテスト -クラスの依存関係や実装ルールをコードとして表現し、自動テスト化する</p> -<ul> -<li>deptrac</li> -<li>phpat</li> -</ul> -<p>Independent Core Layer Pattern</p> -<p>アーキテクチャテストの失敗</p> -<ul> -<li>実装誤り</li> -<li>or アーキテクチャが適切でない -<ul> -<li>開発の過程でフィードバックしていく</li> -</ul> -</li> -</ul> -<p>モジュラーモノリス→マイクロサービスへ</p> -</blockquote> -<h2 id="day-2-20210328">Day 2 (2021/03/28)</h2> -<p>冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。</p> -<p>残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。</p> -<h2 id="全体の感想">全体の感想</h2> -<p>Day 2 にほとんど参加できなかったのは残念だが、イベント自体は大変楽しく、また興味深いものであった。自分がまったく知らない領域の話を聞けるのはこうしたイベントならではだと感じる。オンライン開催ゆえ現地に行く必要がなく、気軽に参加できたのも (特に初参加者として) 嬉しいポイントだった。</p> -<p>今回、雑談/登壇者への質問等向けに Discord サーバもあったのだが、こちらは参加こそしたものの ROM のままになってしまった。発表に1ウィンドウ、メモを書くのに1ウィンドウ、Discord 表示に 1ウィンドウで私にはもう脳のリソースとディスプレイのスペースが追いつかなかった (さらにいうと Zoom でアンカンファレンスもやっていたようだ。こちらはまったく参加していない)。</p> -<p>1つ個人的な反省点としては、一つ一つのセッションを真剣に聞き過ぎたというものがある。もっと適当に聞いておけばよかった。これだけだと大変語弊があるのだが、言い方を変えると、Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。 -まあ初カンファレンスだし、とお茶を濁しておこう。</p> -<p>さて、カンファレンスで一つ気になったことがある。それは、Discord という書き込み場所が増えたことでニコ生のコメントの流量が吸い取られてしまったのではないか、という点だ。ニコニコだけ見ていると過疎っているかのように見えた発表も、Discord の方では盛り上がっている、というのを何度か見かけた。ニコニコのコメント方式は盛り上がりを如実に反映するが、逆もまたしかり。Discord があったこと自体はプラスだったと思うが、この点はマイナスだったのではないかと感じる。</p> -<hr> -<p>最後になりましたが、毎年の PHPerKaigi 開催にご尽力されている皆様、スピーカーの皆様、楽しい3日間でした。ありがとうございました! -(ずっと常体で書いてしまったのでいきなり仏頂面から笑顔になったようで気持ち悪い)</p> -<p>ではまた来年。</p> -]]></description> - </item> - - </channel> -</rss> diff --git a/docs/tags/php/index.html b/docs/tags/php/index.html deleted file mode 100644 index e38f0a9..0000000 --- a/docs/tags/php/index.html +++ /dev/null @@ -1,117 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - - <title>php | REPL: Rest-Eat-Program Loop</title> - - <meta name="description" content=""> - <meta name="author" content="nsfisis"> - - <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet"> - - <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg"> - <meta name="generator" content="Hugo 0.102.1" /> - - <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/php/feed.xml" title="REPL: Rest-Eat-Program Loop" /> - - </head> - <body class="list"> - <header class="header"> - <nav class="nav"> - <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p> - </nav> - </header> - <main class="main"> - -<header class="page-header"><h1>php</h1></header> - -<article class="post-entry"> - <header class="entry-header"> - <h2>PHPerKaigi 2023: ボツになったトークン問題 その 1</h2> - </header> - <section class="entry-content"> - <p>来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、 -ボツになった問題を公開する (その 1)。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2022-10-23</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/"></a> -</article> -<article class="post-entry"> - <header class="entry-header"> - <h2>[PHP] fizzbuzz を書く。1行あたり2文字で。</h2> - </header> - <section class="entry-content"> - <p>PHP で、fizzbuzz を書いた。ただし、1行あたりに使える文字数は2文字まで。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2022-09-29</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/"></a> -</article> -<article class="post-entry"> - <header class="entry-header"> - <h2>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</h2> - </header> - <section class="entry-content"> - <p>PHP カンファレンス沖縄の懇親会 LT で出題されたコードゴルフの問題を解いてみた。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2022-08-27</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/"></a> -</article> -<article class="post-entry"> - <header class="entry-header"> - <h2>PHPerKaigi 2022</h2> - </header> - <section class="entry-content"> - <p>2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に参加した。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2022-05-01</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/"></a> -</article> -<article class="post-entry"> - <header class="entry-header"> - <h2>PHPerKaigi 2022 トークン問題の解説</h2> - </header> - <section class="entry-content"> - <p>PHPerKaigi 2022 で私が作成した PHPer チャレンジ問題を解説する。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2022-04-09</time>, updated on <time>2022-04-16</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/"></a> -</article> -<article class="post-entry"> - <header class="entry-header"> - <h2>PHPerKaigi 2021</h2> - </header> - <section class="entry-content"> - <p>2021-03-26 から 2021-03-28 にかけて開催された、PHPerKaigi 2021 に参加した。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2021-03-30</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/"></a> -</article></main> -<footer class="footer"> - <span>© 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span> - <span>·</span> - <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span> -</footer> -<script src="https://blog.nsfisis.dev/highlight.min.js"></script> -<script> - hljs.initHighlightingOnLoad(); -</script> -</body> -</html> - diff --git a/docs/tags/php/page/1/index.html b/docs/tags/php/page/1/index.html deleted file mode 100644 index 9d866e9..0000000 --- a/docs/tags/php/page/1/index.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <title>https://blog.nsfisis.dev/tags/php/</title> - <link rel="canonical" href="https://blog.nsfisis.dev/tags/php/"> - <meta name="robots" content="noindex"> - <meta charset="utf-8"> - <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/php/"> - </head> -</html> diff --git a/docs/tags/phpcon/feed.xml b/docs/tags/phpcon/feed.xml deleted file mode 100644 index b5b8325..0000000 --- a/docs/tags/phpcon/feed.xml +++ /dev/null @@ -1,61 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> - <channel> - <title>phpcon on REPL: Rest-Eat-Program Loop</title> - <link>https://blog.nsfisis.dev/tags/phpcon/</link> - <description>Recent content in phpcon on REPL: Rest-Eat-Program Loop</description> - <generator>Hugo -- gohugo.io</generator> - <language>ja-JP</language> - <lastBuildDate>Sat, 27 Aug 2022 18:55:28 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/phpcon/feed.xml" rel="self" type="application/rss+xml" /> - <item> - <title>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</title> - <link>https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/</link> - <pubDate>Sat, 27 Aug 2022 18:55:28 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/</guid> - <description><![CDATA[ <h1 id="はじめに">はじめに</h1> -<p>本日 <a href="https://phpcon.okinawa.jp/">PHP カンファレンス沖縄 2022</a> が開催された (らしい)。</p> -<p>カンファレンスには参加できなかったものの、懇親会の LT で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。</p> -<p>ツイート: <a href="https://twitter.com/m3m0r7/status/1563397620231712772">https://twitter.com/m3m0r7/status/1563397620231712772</a> <br> -スライド: <a href="https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3">https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3</a></p> -<h1 id="解">解</h1> -<p>細かいレギュレーションは不明だったので、勝手に定めた。</p> -<ul> -<li>コマンドライン引数の第1引数で受けとる</li> -<li>結果は標準出力に出す</li> -<li>コンマの直後にはスペースを1つ置く</li> -<li>末尾コンマは禁止</li> -<li>数字でないものは入ってこないものとする</li> -<li>負数は入ってこないものとする</li> -</ul> -<p>書いたものがこちら:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>[<span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> $n<span style="color:#f92672">=</span>$argv[<span style="color:#ae81ff">1</span>];<span style="color:#66d9ef">foreach</span>([<span style="color:#ae81ff">1e4</span>,<span style="color:#ae81ff">5e3</span>,<span style="color:#ae81ff">2e3</span>,<span style="color:#ae81ff">1e3</span>,<span style="color:#ae81ff">500</span>,<span style="color:#ae81ff">100</span>,<span style="color:#ae81ff">50</span>,<span style="color:#ae81ff">10</span>,<span style="color:#ae81ff">5</span>,<span style="color:#ae81ff">1</span>]<span style="color:#66d9ef">as</span>$x)<span style="color:#66d9ef">for</span>(;$n<span style="color:#f92672">>=</span>$x;$n<span style="color:#f92672">-=</span>$x)$r[]<span style="color:#f92672">=</span>$x;<span style="color:#66d9ef">echo</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">', '</span>,$r<span style="color:#f92672">??</span>[]);<span style="color:#75715e">?></span><span style="color:#960050;background-color:#1e0010">] -</span></span></span></code></pre></div><p>しめて 123 バイトとなった (末尾改行を含めずにカウント)。</p> -<p>こちらは改行とスペースを追加したバージョン:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>[<span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$n <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>]; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ([<span style="color:#ae81ff">1e4</span>, <span style="color:#ae81ff">5e3</span>, <span style="color:#ae81ff">2e3</span>, <span style="color:#ae81ff">1e3</span>, <span style="color:#ae81ff">500</span>, <span style="color:#ae81ff">100</span>, <span style="color:#ae81ff">50</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">1</span>] <span style="color:#66d9ef">as</span> $x) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> (; $n <span style="color:#f92672">>=</span> $x; $n <span style="color:#f92672">-=</span> $x) -</span></span><span style="display:flex;"><span> $r[] <span style="color:#f92672">=</span> $x; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">', '</span>, $r <span style="color:#f92672">??</span> []); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">?></span><span style="color:#960050;background-color:#1e0010">] -</span></span></span></code></pre></div><h1 id="使用したテクニック">使用したテクニック</h1> -<h2 id="指数表記">指数表記</h2> -<p>割と多くの言語のゴルフで使えるテクニック。<code>e</code> を用いた指数表記で、大きな数を短く表す。このコードでは <code>10000</code>、<code>5000</code>、<code>2000</code>、<code>1000</code> を指数表記している。</p> -<h2 id="foreach-や-for-の中身を1つの文に">foreach や for の中身を1つの文に</h2> -<p><code>foreach</code>、<code>for</code>、<code>if</code> などの後ろには、通常 <code>{</code> を続けて複数の文を連ねるが、中身の文を1つにしてしまえば、<code>{</code> と <code>}</code> を省略できる。C言語などでも使える。</p> -<h2 id="r-に初期値を入れない">$r に初期値を入れない</h2> -<p>PHP では、<code>$r[] = ...</code> のような配列の末尾に追加する式を実行したとき、<code>$r</code> が未定義だった場合は <code>$r</code> を勝手に定義して空の配列で初期化してくれる。これを利用すると、<code>$r = [];</code> のような初期化が不要になる。</p> -<p>ただし、プログラムに 0 が渡されるとループを一度も回らないので、<code>$r</code> が未定義になってしまい、<code>implode()</code> に渡すところでエラーになる。それを防ぐために <code>$r ?? []</code> を使っている。</p> -<p>もし 0 が渡されたケースを無視するなら、これが不要になるので 4 バイト縮む。</p> -<h2 id="php-タグの外に文字列を置く">PHP タグの外に文字列を置く</h2> -<p>PHP では、<code><?php</code> <code>?></code> で囲われた部分の外側にある文字列は、そのまま出力される。今回のケースでは、先頭と末尾に必ず <code>[</code> と <code>]</code> を出力するので、そのまま書いてやればよい。</p> -<h1 id="おわりに">おわりに</h1> -<p>最後になりましたが、<a href="https://twitter.com/m3m0r7">めもりー</a> さん、楽しい問題をありがとうございました。</p> -]]></description> - </item> - - </channel> -</rss> diff --git a/docs/tags/phpcon/index.html b/docs/tags/phpcon/index.html deleted file mode 100644 index d3d3cba..0000000 --- a/docs/tags/phpcon/index.html +++ /dev/null @@ -1,56 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - - <title>phpcon | REPL: Rest-Eat-Program Loop</title> - - <meta name="description" content=""> - <meta name="author" content="nsfisis"> - - <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet"> - - <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg"> - <meta name="generator" content="Hugo 0.102.1" /> - - <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/phpcon/feed.xml" title="REPL: Rest-Eat-Program Loop" /> - - </head> - <body class="list"> - <header class="header"> - <nav class="nav"> - <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p> - </nav> - </header> - <main class="main"> - -<header class="page-header"><h1>phpcon</h1></header> - -<article class="post-entry"> - <header class="entry-header"> - <h2>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</h2> - </header> - <section class="entry-content"> - <p>PHP カンファレンス沖縄の懇親会 LT で出題されたコードゴルフの問題を解いてみた。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2022-08-27</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/"></a> -</article></main> -<footer class="footer"> - <span>© 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span> - <span>·</span> - <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span> -</footer> -<script src="https://blog.nsfisis.dev/highlight.min.js"></script> -<script> - hljs.initHighlightingOnLoad(); -</script> -</body> -</html> - diff --git a/docs/tags/phpcon/page/1/index.html b/docs/tags/phpcon/page/1/index.html deleted file mode 100644 index 736f0cb..0000000 --- a/docs/tags/phpcon/page/1/index.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <title>https://blog.nsfisis.dev/tags/phpcon/</title> - <link rel="canonical" href="https://blog.nsfisis.dev/tags/phpcon/"> - <meta name="robots" content="noindex"> - <meta charset="utf-8"> - <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/phpcon/"> - </head> -</html> diff --git a/docs/tags/phperkaigi/feed.xml b/docs/tags/phperkaigi/feed.xml deleted file mode 100644 index 439bf91..0000000 --- a/docs/tags/phperkaigi/feed.xml +++ /dev/null @@ -1,974 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> - <channel> - <title>phperkaigi on REPL: Rest-Eat-Program Loop</title> - <link>https://blog.nsfisis.dev/tags/phperkaigi/</link> - <description>Recent content in phperkaigi on REPL: Rest-Eat-Program Loop</description> - <generator>Hugo -- gohugo.io</generator> - <language>ja-JP</language> - <lastBuildDate>Sun, 23 Oct 2022 09:54:07 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/phperkaigi/feed.xml" rel="self" type="application/rss+xml" /> - <item> - <title>PHPerKaigi 2023: ボツになったトークン問題 その 1</title> - <link>https://blog.nsfisis.dev/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/</link> - <pubDate>Sun, 23 Oct 2022 09:54:07 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/</guid> - <description><![CDATA[ <h1 id="はじめに">はじめに</h1> -<p>2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) の、<a href="https://phperkaigi.jp/2023/">PHPerKaigi 2023</a> において、昨年と同様に、弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> から、トークン問題を出題予定である。</p> -<p>昨年のトークン問題の記事はこちら: <a href="/posts/2022-04-09/phperkaigi-2022-tokens">PHPerKaigi 2022 トークン問題の解説</a></p> -<p>すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。</p> -<p>10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。</p> -<h1 id="問題">問題</h1> -<p>注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#66d9ef">null</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> ($π <span style="color:#f92672">===</span> <span style="color:#66d9ef">null</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">'No input.'</span>); -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#a6e22e">trim</span>($π); -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">is_numeric</span>($π)) { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">'Invalid input.'</span>); -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>))); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">preg_match</span>(<span style="color:#e6db74">'/(\x23.+?) /'</span>, $s, $m); -</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> $m[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#e6db74">''</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">md5</span>($t) <span style="color:#f92672">===</span> <span style="color:#e6db74">'056e831a4146bf123e8ea16613303d2e'</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">"Token: </span><span style="color:#e6db74">{</span>$t<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>; -</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">else</span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">"Failed.</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>; -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><h1 id="トークン入手方法">トークン入手方法</h1> -<p>ソースを見るとわかるとおり、<code>$argv[1]</code> を参照している。それを <code>$π</code> なる変数に代入しているので、円周率を渡してみる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.14 -</span></span><span style="display:flex;"><span>Failed. -</span></span></code></pre></div><p>失敗してしまった。精度を上げてみる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.1415 -</span></span><span style="display:flex;"><span>Failed. -</span></span></code></pre></div><p>だめだった。これを成功するまで繰り返す。</p> -<p>最初にトークンが得られるのは、小数点以下 16 桁目まで入力したときで、こうなる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.1415926535897932 -</span></span><span style="display:flex;"><span>Token: #YO -</span></span></code></pre></div><p>めでたくトークン「#YO」が手に入った。</p> -<h1 id="解説">解説</h1> -<p>短いので頭から追っていく。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#66d9ef">null</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> ($π <span style="color:#f92672">===</span> <span style="color:#66d9ef">null</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">'No input.'</span>); -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#a6e22e">trim</span>($π); -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">is_numeric</span>($π)) { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">'Invalid input.'</span>); -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>入力のバリデーション部分。数値のみ受け付ける。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>))); -</span></span></code></pre></div><p><code>$π</code> を 2 文字ごとに区切り (<code>str_split</code>)、数値を ASCII コードと見做して文字に変換 (<code>chr</code>) して結合 (<code>implode</code>) している。</p> -<p>例えば、<code>$π</code> が <code>'656667'</code> だったとすると、<code>65</code>、<code>66</code>、<code>67</code> に対応した <code>'A'</code>、<code>'B'</code>、<code>'C'</code> へと変換され、<code>'ABC'</code> になる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#e6db74">'656667'</span>; -</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>))); -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> $s; -</span></span><span style="display:flex;"><span><span style="color:#75715e">// => ABC -</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">preg_match</span>(<span style="color:#e6db74">'/(\x23.+?) /'</span>, $s, $m); -</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> $m[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#e6db74">''</span>; -</span></span></code></pre></div><p>正規表現でマッチングしている。<code>\x23</code> は <code>#</code> と同じであることに留意すると、この正規表現は「<code>#</code> から始まる 2 以上の長さ (含 <code>#</code>) の文字列で、最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi におけるトークンである。</p> -<p>なお、<code>#</code> を直接書いていないのは、<code>/#.+?) /</code> と書くと、<code>#.+?)</code> という意図せぬトークンが登録されてしまうからである。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">md5</span>($t) <span style="color:#f92672">===</span> <span style="color:#e6db74">'056e831a4146bf123e8ea16613303d2e'</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">"Token: </span><span style="color:#e6db74">{</span>$t<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>; -</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">else</span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">"Failed.</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>; -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>最後にトークンのハッシュ値を見て、想定解かどうかを確認する。</p> -<h1 id="おわりに">おわりに</h1> -<p>円周率を何桁も計算して ASCII コード経由で文字列化すれば、トークンっぽいものがどこかで出てくるのではないか、と考えて生まれた作品。</p> -<p>最初は真面目に円周率の計算プログラムを組んでいたのだが、いざ動かしてみるとやけに浅いところにあったので驚いた (ちなみに、それでも <code>M_PI</code> や <code>pi()</code> では精度が足りない)。見つけたときは狂喜したものの、冷静になってみると大して面白くなかったのでボツになった。むしろ、100 万桁目くらいに埋まっていてくれたほうがよかったかもしれない。</p> -]]></description> - </item> - - <item> - <title>PHPerKaigi 2022</title> - <link>https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/</link> - <pubDate>Sun, 01 May 2022 09:41:39 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/</guid> - <description><![CDATA[ <h1 id="はじめに">はじめに</h1> -<p>2022-04-09 から 2022-04-11 にかけて開催された、<a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> に、一般参加者として参加した。 -弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p> -<p>昨年のレポートは<a href="/posts/2021-03-30/phperkaigi-2021">こちら</a>。</p> -<h1 id="感想">感想</h1> -<h2 id="厳選おすすめトーク">厳選おすすめトーク</h2> -<p>多くの素晴らしいトークの中から、特におすすめのものを 5つ選んだ。是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。</p> -<p><a href="https://fortee.jp/phperkaigi-2022/proposal/ef8cf4ed-63fe-42f8-8145-b3e70054458b">予防に勝る防御なし - 堅牢なコードを導く様々な設計のヒント</a></p> -<blockquote> -<p>PHP はバージョンを追う毎に型宣言、例外、表明、列挙型などの機能が大幅に強化され、堅牢なコードを書くための機能が充実してきました。それらの機能はどう使うと効果的なのでしょうか。</p> -<p>本講演では PHP 8.1 をベースにして、誤りを想定してチェックするのではなく、そもそも誤りにくい設計とはどのようなものか、つまり「予防」の観点を軸足に、堅牢なコードを導くための様々な設計のヒントをご紹介します。</p> -</blockquote> -<p><a href="https://fortee.jp/phperkaigi-2022/proposal/db00d49e-0dd6-453f-b54b-f731d112f10e">PHPのエラーを理解して適切なエラーハンドリングを学ぼう</a></p> -<blockquote> -<p>PHPを使ってるとよく遭遇する Fatal error / Parse error / Warning / Notice 理解していますか?<br> -これらのエラー文を理解することで、すぐにエラーの原因に気付き適切に対象できる様になります!<br> -またそれらを理解した上でのエラーハンドリングを学びましょう。</p> -</blockquote> -<p><a href="https://fortee.jp/phperkaigi-2022/proposal/4a7e3ded-9134-4919-955c-ec7bf4491c0d">エラー監視とテスト体制への改善作戦</a></p> -<blockquote> -<p>毎日流れてくるエラーに皆さんはどう向き合ってますか?<br> -エラーを出さない事が一番ですが、完全に塞ぐ事は難しいと考えます。<br> -サービス運用の中で本番環境から発生するエラー(サーバー・クライアントサイド・サードパーティ起因のエラー)への監視体制と、<br> -エラー・バグ防御のためチームで行っているテストコード文化づくりの話をします。</p> -</blockquote> -<p><a href="https://fortee.jp/phperkaigi-2022/proposal/6f47daf8-c78f-4fb1-9b99-e9656e6fe7f7">ISUCON11のPHP実装は、何を考え、どのようにして作られていたのか</a></p> -<blockquote> -<p>昨年開催されたISUCON11にて問題(参考実装)のPHPへの移植を担当させていただきました。</p> -<p>最終的なソースコードこそシンプルなWebアプリケーションではありますが、その裏には<br> -・「(私の思う)良い設計」を実現するための意思決定<br> -・「ISUCONの問題」という位置付けに由来する取捨選択<br> -・移植中に遭遇したトラブルとその解決策<br> -といった文脈や葛藤が存在しています。</p> -<p>本発表はそれらを共有することで<br> -・PHPアプリケーションの設計、実装事例として役立ててもらう<br> -・ISUCONの言語移植に興味を持ってもらう<br> -・ISUCON問題移植の「実装や設計の練習をする教材」としての可能性を知ってもらう<br> -ことを目的とします。</p> -</blockquote> -<p><a href="https://fortee.jp/phperkaigi-2022/proposal/5a260e4e-542d-4d82-849d-ef3d6cb7c854">チームの仕事はまわっていたけど、メンバーはそれぞれモヤモヤを抱えていた話──40名の大規模開発チームで1on1ログを公開してみた</a></p> -<blockquote> -<p>サイボウズの大企業向けグループウェアのGaroon(ガルーン)は、PHPで開発されている20年目の製品です。ガルーン開発チームは日本で40名、ベトナムで50名の計90名ほどのチームになっています。また、コロナ禍でフルリモートでの活動がこの2年ほど継続してきました。</p> -<p>フルリモートになっても仕事はまわっており、継続的にリリースはしていましたが、一方でお互いの考えていることや感じている問題意識が見えづらくなり、モヤモヤを抱えているメンバーが増えていました。</p> -<p>このセッションでは、そういう状況で私がチーム外からジョインし、聴き役に徹しながら見える化することで状況を改善していった取り組みを紹介します。同じように大きなチームやリモートワークで難しさを感じている人に、難しさの原因への気づきや取り組みへのヒントがあれば幸いです。</p> -</blockquote> -<h2 id="トークン問題の作成">トークン問題の作成</h2> -<p>今回は、PHPer チャレンジ用に弊社のトークン問題を 3題作成した。こちらについては<a href="/posts/2022-04-09/phperkaigi-2022-tokens">別途記事にしている</a>ので、そちらを参照されたい。</p> -<h2 id="phper-チャレンジ">PHPer チャレンジ</h2> -<p><a href="https://fortee.jp/phperkaigi-2022/challenge">1位</a>になった。<br> -また、賞品として <a href="https://www.amazon.co.jp/dp/B08MQNJC9Z">Echo Show 15</a> をいただいた。</p> -<h2 id="カンファレンス全体への感想">カンファレンス全体への感想</h2> -<p><a href="/posts/2021-03-30/phperkaigi-2021">去年の参加レポ</a> では、こんなことを書いた。</p> -<blockquote> -<p>1つ個人的な反省点としては、(中略) Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。<br> -まあ初カンファレンスだし、とお茶を濁しておこう。</p> -</blockquote> -<p>この反省を踏まえ、今年は積極的にほかの場 (公式の Discord サーバや、アンカンファレンス) にも参加した。<br> -これにより、参加体験の質がはるかに向上した。特に Discord に関しては、登壇者ご本人による補足や、質問への回答などがおこなわれる (ことが多い) ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。</p> -<p>なお、アンカンファレンスについては、1日目の終わりに<a href="https://fortee.jp/phperkaigi-2022/unconference/view/d332797a-8921-4706-a7e2-ee72640c9b5e">トークン問題の解説放送</a>もおこなった。</p> -<p>また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。 -今年は 3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。</p> -<h1 id="そして来年へ">そして来年へ……?</h1> -<p>PHPerKaigi 2023 があるかどうか存じ上げないが、あるとすれば、次の 4つを目標としたい。</p> -<ul> -<li>プロポーザルを出す</li> -<li>PHPer チャレンジのトークン問題を 5題作成する</li> -<li>現地に行く</li> -<li>PHPer チャレンジで圧勝する</li> -</ul> -<hr> -<p>最後になりましたが、PHPerKaigi のスタッフ、スポンサー、スピーカーのみなさん、素敵な時間をありがとうございました。</p> -<p>ではまた来年。</p> -]]></description> - </item> - - <item> - <title>PHPerKaigi 2022 トークン問題の解説</title> - <link>https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/</link> - <pubDate>Sat, 09 Apr 2022 21:50:19 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/</guid> - <description><![CDATA[ <h1 id="はじめに">はじめに</h1> -<p>本日開始された <a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> の PHPer チャレンジにおいて、弊社 <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> の問題を 3問作成した。この記事では、これらの問題の解説をおこなう。</p> -<p>リポジトリはこちら: <a href="https://github.com/nsfisis/PHPerKaigi2022-tokens">https://github.com/nsfisis/PHPerKaigi2022-tokens</a></p> -<h1 id="第1問-brainf_ckphp">第1問 brainf_ck.php</h1> -<p>ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">declare</span>(<span style="color:#a6e22e">strict_types</span><span style="color:#f92672">=</span><span style="color:#ae81ff">0</span><span style="color:#a6e22e">O1</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">namespace</span> <span style="color:#a6e22e">Dgcircus\PHPerKaigi\Y2022</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#e6db74">/** -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * @todo -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Run this program to acquire a PHPer token. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> */</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">https</span><span style="color:#f92672">://</span><span style="color:#a6e22e">creativecommons</span><span style="color:#f92672">.</span><span style="color:#a6e22e">org</span><span style="color:#f92672">/</span><span style="color:#a6e22e">publicdomain</span><span style="color:#f92672">/</span><span style="color:#a6e22e">zero</span><span style="color:#f92672">/</span><span style="color:#ae81ff">1.0</span><span style="color:#f92672">/</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">\error_reporting</span>(<span style="color:#f92672">~+!</span><span style="color:#e6db74">'We are hiring!'</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$z <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($f) <span style="color:#f92672">=></span> (<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=></span> $f(<span style="color:#a6e22e">fn</span>(<span style="color:#f92672">...</span>$xs) <span style="color:#f92672">=></span> $x($x)(<span style="color:#f92672">...</span>$xs)))(<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=></span> $f(<span style="color:#a6e22e">fn</span>(<span style="color:#f92672">...</span>$xs) <span style="color:#f92672">=></span> $x($x)(<span style="color:#f92672">...</span>$xs))); -</span></span><span style="display:flex;"><span>$id <span style="color:#f92672">=</span> <span style="color:#a6e22e">\spl_object_id</span>(<span style="color:#f92672">...</span>); -</span></span><span style="display:flex;"><span>$put <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($c) <span style="color:#f92672">=></span> <span style="color:#a6e22e">\printf</span>(<span style="color:#e6db74">'%c'</span>, $c); -</span></span><span style="display:flex;"><span>$mm <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($p, $n) <span style="color:#f92672">=></span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">\ArrayObject</span>(<span style="color:#a6e22e">\array_fill</span>(<span style="color:#f92672">+!!</span>[], $n, $p)); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$👉 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> [<span style="color:#f92672">++</span>$mp, <span style="color:#f92672">++</span>$pc]; -</span></span><span style="display:flex;"><span>$👈 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> [<span style="color:#f92672">--</span>$mp, <span style="color:#f92672">++</span>$pc]; -</span></span><span style="display:flex;"><span>$👍 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> [$mp, <span style="color:#f92672">++</span>$pc, <span style="color:#f92672">++</span>$m[$mp]]; -</span></span><span style="display:flex;"><span>$👎 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> [$mp, <span style="color:#f92672">++</span>$pc, <span style="color:#f92672">--</span>$m[$mp]]; -</span></span><span style="display:flex;"><span>$📝 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> [$mp, <span style="color:#f92672">++</span>$pc, $put($m[$mp])]; -</span></span><span style="display:flex;"><span>$🤡 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> <span style="color:#a6e22e">match</span> ($m[$mp]) { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">=></span> [$mp, $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=></span> <span style="color:#a6e22e">fn</span>($pc, $n) <span style="color:#f92672">=></span> <span style="color:#a6e22e">match</span> ($id($p[$pc])) { -</span></span><span style="display:flex;"><span> $b <span style="color:#f92672">=></span> $loop(<span style="color:#f92672">++</span>$pc, <span style="color:#f92672">++</span>$n), -</span></span><span style="display:flex;"><span> $e <span style="color:#f92672">=></span> $n <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">?</span> <span style="color:#f92672">++</span>$pc <span style="color:#f92672">:</span> $loop(<span style="color:#f92672">++</span>$pc, <span style="color:#f92672">--</span>$n), -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=></span> $loop(<span style="color:#f92672">++</span>$pc, $n), -</span></span><span style="display:flex;"><span> })($pc, <span style="color:#f92672">-!</span>[])], -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=></span> [$mp, <span style="color:#f92672">++</span>$pc], -</span></span><span style="display:flex;"><span>}; -</span></span><span style="display:flex;"><span>$🎪 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> <span style="color:#a6e22e">match</span> ($m[$mp]) { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">=></span> [$mp, <span style="color:#f92672">++</span>$pc], -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=></span> [$mp, $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=></span> <span style="color:#a6e22e">fn</span>($pc, $n) <span style="color:#f92672">=></span> <span style="color:#a6e22e">match</span> ($id($p[$pc])) { -</span></span><span style="display:flex;"><span> $e <span style="color:#f92672">=></span> $loop(<span style="color:#f92672">--</span>$pc, <span style="color:#f92672">++</span>$n), -</span></span><span style="display:flex;"><span> $b <span style="color:#f92672">=></span> $n <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">?</span> $pc<span style="color:#f92672">+!</span>[] <span style="color:#f92672">:</span> $loop(<span style="color:#f92672">--</span>$pc, <span style="color:#f92672">--</span>$n), -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=></span> $loop(<span style="color:#f92672">--</span>$pc, $n), -</span></span><span style="display:flex;"><span> })($pc, <span style="color:#f92672">-!</span>[])], -</span></span><span style="display:flex;"><span>}; -</span></span><span style="display:flex;"><span>$🐘 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($p) <span style="color:#f92672">=></span> $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=></span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=></span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">isset</span>($p[$pc]) <span style="color:#f92672">&&</span> $loop($m, $p, $b, $e, <span style="color:#f92672">...</span>($p[$pc]($m, $p, $b, $e, $mp, $pc))) -</span></span><span style="display:flex;"><span>)($mm(<span style="color:#f92672">+!!</span>[], <span style="color:#f92672">+</span>(<span style="color:#f92672">!</span>[]<span style="color:#f92672">.!</span>[])), $p, $id($🤡), $id($🎪), <span style="color:#f92672">+!!</span>[], <span style="color:#f92672">+!!</span>[]); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$🐘([ -</span></span><span style="display:flex;"><span> $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, -</span></span><span style="display:flex;"><span> $🤡, -</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, -</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, -</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, -</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, -</span></span><span style="display:flex;"><span> $👈, $👈, $👈, $👈, $👎, -</span></span><span style="display:flex;"><span> $🎪, -</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $📝, -</span></span><span style="display:flex;"><span> $👎, $👎, $📝, -</span></span><span style="display:flex;"><span> $👉, $👎, $👎, $👎, $📝, -</span></span><span style="display:flex;"><span> $👉, $👎, $👎, $👎, $📝, -</span></span><span style="display:flex;"><span> $👎, $👎, $📝, -</span></span><span style="display:flex;"><span> $👎, $📝, -</span></span><span style="display:flex;"><span> $👈, $📝, -</span></span><span style="display:flex;"><span> $👉, $👉, $👎, $👎, $📝, -</span></span><span style="display:flex;"><span> $👍, $👍, $👍, $👍, $👍, $👍, $👍, $📝, -</span></span><span style="display:flex;"><span> $👈, $👎, $👎, $👎, $👎, $📝, -</span></span><span style="display:flex;"><span> $👈, $📝, -</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $📝, -</span></span><span style="display:flex;"><span> $👉, $👎, $📝, -</span></span><span style="display:flex;"><span> $👈, $📝, -</span></span><span style="display:flex;"><span>]); -</span></span></code></pre></div><p>この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。</p> -<h2 id="解説">解説</h2> -<h3 id="絵文字">絵文字</h3> -<p>まず目につくのは大量の絵文字だろう。 -PHP は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。</p> -<h3 id="プログラム全体">プログラム全体</h3> -<p>Brainf*ck のインタプリタとプログラムになっている。 -Brainf*ck とは、難解プログラミング言語のひとつであり、ここで説明するよりも Wikipedia の該当ページを読んだ方がよい。</p> -<p><a href="https://ja.wikipedia.org/wiki/Brainfuck">https://ja.wikipedia.org/wiki/Brainfuck</a></p> -<p>なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。</p> -<pre tabindex="0"><code>+ + + + + + + + + + -[ - > + + + - > + + + + + - > + + + + + + + + + + + + - > + + + + + + + + + + - < < < < - -] -> + + + + + . -- - . -> - - - . -> - - - . -- - . -- . -< . -> > - - . -+ + + + + + + . -< - - - - . -< . -> + + . -> - . -< . -</code></pre><p>実行結果はこちら: <a href="https://ideone.com/22VWmb">https://ideone.com/22VWmb</a></p> -<p>それぞれの絵文字で表された関数が、各命令に対応している。</p> -<ul> -<li><code>$👉</code>: <code>></code></li> -<li><code>$👈</code>: <code><</code></li> -<li><code>$👍</code>: <code>+</code></li> -<li><code>$👎</code>: <code>-</code></li> -<li><code>$📝</code>: <code>.</code></li> -<li><code>$🤡</code>: <code>[</code></li> -<li><code>$🎪</code>: <code>]</code></li> -</ul> -<p><code>,</code> (入力) に対応する関数はない (このプログラムでは使わないので用意していない)。</p> -<p>なお、<code>$🐘</code> はいわゆる main 関数であり、プログラムの実行部分である。</p> -<h3 id="絵文字の選択">絵文字の選択</h3> -<p>おおよそ意味に合致するよう選んでいるが、<code>$🤡</code> と <code>$🎪</code> は弊社デジタルサーカスにちなんでいる。 -また、<code>$🐘</code> は PHP のマスコットの象に由来する。</p> -<h3 id="strict_types">strict_types</h3> -<p><code>declare</code> 文の <code>strict_types</code> に指定できるのは、<code>0</code> か <code>1</code> の数値リテラルだが、 -<code>0x0</code> や <code>0b1</code> のような値も受け付ける。 -今回は、PHP 8.1 から追加された、<code>0O</code> または <code>0o</code> から始まる八進数リテラルを使った。</p> -<h3 id="url">URL</h3> -<p>ソースコードのライセンスを示したこの部分だが、</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">https</span><span style="color:#f92672">://</span><span style="color:#a6e22e">creativecommons</span><span style="color:#f92672">.</span><span style="color:#a6e22e">org</span><span style="color:#f92672">/</span><span style="color:#a6e22e">publicdomain</span><span style="color:#f92672">/</span><span style="color:#a6e22e">zero</span><span style="color:#f92672">/</span><span style="color:#ae81ff">1.0</span><span style="color:#f92672">/</span> -</span></span></code></pre></div><p>完全に合法な PHP のコードである。 -<code>https:</code> 部分はラベル、<code>//</code> 以降は行コメントになっている。</p> -<h3 id="リテラルなしで数値を生成する">リテラルなしで数値を生成する</h3> -<p>ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。 -PHP では、型変換を利用することで任意の整数を作り出すことができる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[]); -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">1</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+!</span>[]); -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">2</span> <span style="color:#f92672">===</span> <span style="color:#f92672">!</span>[]<span style="color:#f92672">+!</span>[]); -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">3</span> <span style="color:#f92672">===</span> <span style="color:#f92672">!</span>[]<span style="color:#f92672">+!</span>[]<span style="color:#f92672">+!</span>[]); -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">10</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+</span>(<span style="color:#f92672">!</span>[]<span style="color:#f92672">.+!!</span>[])); -</span></span></code></pre></div><p><code>[]</code> に <code>!</code> を適用すると <code>true</code> が返ってくる。それに <code>+</code> -を適用すると、<code>bool</code> から <code>int</code> ヘの型変換が走り、<code>1</code> が生成される。<code>10</code> -はさらにトリッキーだ。まず <code>1</code> と <code>0</code> を作り、<code>.</code> で文字列として結合する -(<code>'10'</code>)。これに <code>+</code> を適用すると、<code>string</code> から <code>int</code> -への型変換が走り、<code>10</code> が生まれる (コード量に頓着しないなら、<code>1</code> を 10 -個足し合わせてももちろん 10 が作れる)。</p> -<p>また、<code>error_reporting</code> に指定しているのは <code>-1</code> である。 -これは、<code>!</code> によって文字列を <code>false</code> にし、<code>+</code> によって <code>false</code> を <code>0</code> にし、さらにビット反転して <code>-1</code> にしている。</p> -<h3 id="if-文なしで条件分岐"><code>if</code> 文なしで条件分岐</h3> -<p>三項演算子ないし <code>match</code> 式を使うことで、<code>if</code> を一切書かずに条件分岐ができる。 -また、<code>&&</code> / <code>||</code> も使えることがある。 -遅延評価が不要なケースでは、<code>[$t, $f][$cond]</code> のような形で分岐することもできる。</p> -<h3 id="whilefor-文なしでループ"><code>while</code>、<code>for</code> 文なしでループ</h3> -<p>不動点コンビネータを使って無名再帰する (詳しい説明は省略する。これらの単語で検索してほしい)。 -ここでは、一般に Z コンビネータとして知られるものを使った (<code>$z</code>)。</p> -<p>実際のところ、<code>$🤡</code> や <code>$🎪</code>、<code>$🐘</code> は、一度 Scheme (Lisp の一種) で書いてから PHP に翻訳する形で記述した。</p> -<p>なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) ので、 -あまりに長い brainf*ck プログラムを書くとスタックオーバーフローする。</p> -<h1 id="第2問-riddlephp">第2問 riddle.php</h1> -<p>ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#e6db74">/********************************************************* -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * This program displays a PHPer token. * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Guess 'N'. * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Hints: * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - N itself has no special meaning, e.g., 42, 8128, * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * it is selected at random. * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - Each element of $token represents a single letter. * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - One letter consists of 5x5 cells. * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - Remember, the output is a complete PHPer token. * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * License: * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * https://creativecommons.org/publicdomain/zero/1.0/ * -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> *********************************************************/</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">N</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> <span style="color:#75715e">/* Change it to your answer. */</span>; -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672"><=</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&&</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672"><=</span> <span style="color:#ae81ff">0</span><span style="color:#a6e22e">b11111_11111_11111_11111_11111</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$token <span style="color:#f92672">=</span> [ -</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x14B499C</span>, -</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x0BE34CC</span>, <span style="color:#ae81ff">0x01C9C69</span>, -</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x0ECA069</span>, <span style="color:#ae81ff">0x01C2449</span>, <span style="color:#ae81ff">0x0FDB166</span>, <span style="color:#ae81ff">0x01C9C69</span>, -</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x01C1C66</span>, <span style="color:#ae81ff">0x0FC1C47</span>, <span style="color:#ae81ff">0x01C1C66</span>, -</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x10C5858</span>, <span style="color:#ae81ff">0x1E4E3B8</span>, <span style="color:#ae81ff">0x1A2F2F8</span>, -</span></span><span style="display:flex;"><span>]; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($token <span style="color:#66d9ef">as</span> $x) { -</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">'%025b'</span>, $x); -</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">'0'</span>, <span style="color:#e6db74">'1'</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">' '</span>, <span style="color:#e6db74">'#'</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x); -</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>)); -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">"</span><span style="color:#e6db74">{</span>$x<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n\n</span><span style="color:#e6db74">"</span>; -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。 -トークンを得るためには、ソースコードを読み、定数 <code>N</code> を特定する必要がある。</p> -<p>ここでは、私の想定解を解説する。</p> -<h2 id="読解">読解</h2> -<p>まずはソースコードを読んでいく。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$token <span style="color:#f92672">=</span> [ -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 略 -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>]; -</span></span></code></pre></div><p>数値からなる <code>$token</code> があり、各要素をループしている。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>; -</span></span></code></pre></div><p>まずは排他的論理和 (xor) を取り、</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">'%025b'</span>, $x); -</span></span></code></pre></div><p>二進数に変換して、</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">'0'</span>, <span style="color:#e6db74">'1'</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">' '</span>, <span style="color:#e6db74">'#'</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x); -</span></span></code></pre></div><p>0 を空白に、1 を <code>#</code> にし、</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>)); -</span></span></code></pre></div><p>5文字ごとに区切ったあと、改行で結合している。</p> -<h2 id="ヒント">ヒント</h2> -<p>次に、ソースコードに書いてあるヒントを読んでいく。</p> -<ul> -<li><code>N</code> それ自体は、42 や 8128 といったような特別な意味を持たず、ランダムに決められている</li> -<li><code>$token</code> の各要素は、1文字を表す</li> -<li>1文字は 5x5 のセルからなる</li> -<li>出力されるのは、完全な PHPer トークンである</li> -</ul> -<p>ここで、PHPer トークンは必ず <code>#</code> 記号から始まることを思いだすと、 -<code>$token</code> の最初の数字 <code>0x14B499C</code> は、変換の結果 <code>#</code> になるのではないかと予想される (なお、このことは、リポジトリの README ファイルに追加ヒントとして書かれている)。</p> -<h2 id="解く">解く</h2> -<p>ここまでわかれば、あと一歩で解ける。すなわち、<code>0x14B499C</code> が <code>#</code> に変換されるような <code>N</code> を見つければよい。</p> -<p><code>N</code> は高々</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672"><=</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&&</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672"><=</span> <span style="color:#ae81ff">0</span><span style="color:#a6e22e">b11111_11111_11111_11111_11111</span>); -</span></span></code></pre></div><p>なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0x14B499C</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">'%025b'</span>, $x); -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">'0'</span>, <span style="color:#e6db74">'1'</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">' '</span>, <span style="color:#e6db74">'#'</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x); -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>)); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>($x <span style="color:#f92672">===</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">" # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">" # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">" # # "</span>); -</span></span></code></pre></div><p>この一連の変換に対する逆変換を考えると、次のようになる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">" # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">" # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span> <span style="color:#f92672">.</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">" # # "</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">''</span>, <span style="color:#a6e22e">explode</span>(<span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>, $x)); -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">' '</span>, <span style="color:#e6db74">'#'</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">'0'</span>, <span style="color:#e6db74">'1'</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x); -</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">bindec</span>($x); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$n <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#ae81ff">0x14B499C</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">"N = </span><span style="color:#e6db74">$n\n</span><span style="color:#e6db74">"</span>; -</span></span></code></pre></div><p>これを実行すると、<code>N</code> が得られる。</p> -<h1 id="第3問-toquinephp">第3問 toquine.php</h1> -<p>ソースコードはこちら。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672"><?</span><span style="color:#a6e22e">php</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">// License: https://creativecommons.org/publicdomain/zero/1.0/ -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// This is a quine-like program to generate a PHPer token. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// Execute it like this: php toquine.php | php | php | php | ... -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> -</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#e6db74"><<<'</span><span style="color:#e6db74">Q</span><span style="color:#e6db74">' -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"><?cuc -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Yvprafr: uggcf://perngvirpbzzbaf.bet/choyvpqbznva/mreb/1.0/ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Guvf vf n dhvar-yvxr cebtenz gb trarengr n CUCre gbxra. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Rkrphgr vg yvxr guvf: cuc gbdhvar.cuc | cuc | cuc | cuc | ... -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%f$f = %f; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$f = fge_ebg13($f); $kf = [ -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%f, -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">]; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$g = ahyy.snyfr; sbe ($v = 0; $v <= vagqvi(__YVAR__-035,6); ++$v) vs (!vffrg($kf[$v])) oernx; ryfr -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$g .= vzcybqr("\a", fge_fcyvg(fge_ercynpr(['0','1'], [' ','##'], fcevags(pue(37) . '025o', $kf[$v])), 012)) . "\a\a"; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$jf = neenl_znc(sa($j) => vzcybqr(', ', $j), neenl_puhax(neenl_znc(sa($k) => fcevags('0k' . pue(37) . '07K', $k), $kf), 10)); -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">cevags($f, $g, fge_ebg13("<<<'Q'\a{$f}\aQ"), vzcybqr(",\a", $jf)); -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span><span style="color:#e6db74">Q</span>; -</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_rot13</span>($s); $xs <span style="color:#f92672">=</span> [ -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x0AFABEA</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F2109F</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x0002800</span>, <span style="color:#ae81ff">0x1F2109F</span>, <span style="color:#ae81ff">0x0117041</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1F295B7</span>, -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x010FC21</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1151151</span>, <span style="color:#ae81ff">0x010FC21</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F295B7</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F295B7</span>, <span style="color:#ae81ff">0x1F8C63F</span>, -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x1F8C631</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x17AD6BD</span>, <span style="color:#ae81ff">0x17AD6BD</span>, <span style="color:#ae81ff">0x1F8C63F</span>, <span style="color:#ae81ff">0x1F295B7</span>, -</span></span><span style="display:flex;"><span>]; -</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">.</span><span style="color:#66d9ef">false</span>; <span style="color:#66d9ef">for</span> ($i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; $i <span style="color:#f92672"><=</span> <span style="color:#a6e22e">intdiv</span>(<span style="color:#66d9ef">__LINE__</span><span style="color:#f92672">-</span><span style="color:#ae81ff">035</span>,<span style="color:#ae81ff">6</span>); <span style="color:#f92672">++</span>$i) <span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">isset</span>($xs[$i])) <span style="color:#66d9ef">break</span>; <span style="color:#66d9ef">else</span> -</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">.=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">"</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>, <span style="color:#a6e22e">str_split</span>(<span style="color:#a6e22e">str_replace</span>([<span style="color:#e6db74">'0'</span>,<span style="color:#e6db74">'1'</span>], [<span style="color:#e6db74">' '</span>,<span style="color:#e6db74">'##'</span>], <span style="color:#a6e22e">sprintf</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#ae81ff">37</span>) <span style="color:#f92672">.</span> <span style="color:#e6db74">'025b'</span>, $xs[$i])), <span style="color:#ae81ff">012</span>)) <span style="color:#f92672">.</span> <span style="color:#e6db74">"</span><span style="color:#ae81ff">\n\n</span><span style="color:#e6db74">"</span>; -</span></span><span style="display:flex;"><span>$ws <span style="color:#f92672">=</span> <span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">fn</span>($w) <span style="color:#f92672">=></span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">', '</span>, $w), <span style="color:#a6e22e">array_chunk</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=></span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">'0x'</span> <span style="color:#f92672">.</span> <span style="color:#a6e22e">chr</span>(<span style="color:#ae81ff">37</span>) <span style="color:#f92672">.</span> <span style="color:#e6db74">'07X'</span>, $x), $xs), <span style="color:#ae81ff">10</span>)); -</span></span><span style="display:flex;"><span><span style="color:#a6e22e">printf</span>($s, $t, <span style="color:#a6e22e">str_rot13</span>(<span style="color:#e6db74">"<<<'D'</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">{</span>$s<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">D"</span>), <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">",</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">"</span>, $ws)); -</span></span></code></pre></div><p>コメントにもあるとおり、次のようにして実行すれば答えがでてくる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php toquine.php | php | php | php | ... -</span></span></code></pre></div><p>実際にはもう少しパイプで繋げなければならない。</p> -<h2 id="解説-1">解説</h2> -<h3 id="プログラム全体-1">プログラム全体</h3> -<p>コメントにもあるとおり、これは quine (風) のプログラムになっている。 -Quine とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。</p> -<p>このプログラムは、実行すると自身とほとんど同じプログラムを出力する。 -異なるのはトークンになっている部分のみである。</p> -<h3 id="トークン">トークン</h3> -<p><code>$xs</code> がトークンに対応している。変換のロジックは <code>riddle.php</code> とほぼ同じなので省略する。</p> -<h3 id="状態保持">状態保持</h3> -<p>トークンの何文字目まで出力したかを、ソースコードを変えずに (quine なので) 覚えておく必要がある。 -このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、<code>__LINE__</code> から情報を取得している。</p> -<h3 id="rot-13">ROT 13</h3> -<p>Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。 -これがあまり美しくないので、<code>toquine.php</code> では、ROT 13 変換を使って難読化した。</p> -<p>それにしてもなぜこんなものが標準ライブラリに……。</p> -<h1 id="おわりに">おわりに</h1> -<p>解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。</p> -<p>今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、 -来年は 5問、より面白い問題を持っていきます。</p> -<p>実はもう作りはじめているので、どうか来年もありますように……。</p> -]]></description> - </item> - - <item> - <title>PHPerKaigi 2021</title> - <link>https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/</link> - <pubDate>Tue, 30 Mar 2021 23:22:40 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/</guid> - <description><![CDATA[ <h1 id="phperkaigi-2021-参加レポ">PHPerKaigi 2021 参加レポ</h1> -<p>2021-03-26 から 2021-03-28 にかけて開催された、<a href="https://phperkaigi.jp/2021/">PHPerKaigi 2021</a> に一般参加者として参加した。 -弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> (今年1月から勤務) はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p> -<p>このようなカンファレンスには初めて参加するのでかねてより心待ちにしていたのだが、生憎2日目から体調を崩してしまい、この記事も途中までとなっている。まだ見ていないセッションも多いが、ひとまず現時点での参加レポを書いておく。</p> -<p>発表はトラック A、B に分かれていたのだが、今回はすべて A トラックを視聴している (切り替えるのが面倒だっただけ)。</p> -<h2 id="凡例">凡例</h2> -<blockquote> -<p>発表・スライドのメモ (引用ではない)</p> -</blockquote> -<p>感想など</p> -<h2 id="day-0-前夜祭-20210327">Day 0 前夜祭 (2021/03/27)</h2> -<h3 id="1730-a">17:30 [A]</h3> -<p>PHP で AWS Lambda</p> -<blockquote> -<p>Rails のプロジェクトを PHPer のメンバのみでメンテ -→他のメンバもわかる PHP にリプレースを検討</p> -<p>サーバレス</p> -<ul> -<li>サーバ・インフラの管理が不要</li> -<li>アプリケーションコードの知識だけで保守可能</li> -</ul> -<p>ゼロベースで作れる案件が (Railsの件とは別に) あるため、そちらで試験的に導入?</p> -<p>AWSの学習 -AWS のドキュメント -DevelopersIO</p> -<p>AWS Lambda のカスタムランタイムで PHP を動かす</p> -<p>サーバのセットアップや維持管理を気にしなくて良い -サーバーレスで PHP を動かすツールがすでにある -サーバーレス構築はすんなり</p> -<p>今は Laravel がルーティングしている -Laravel Livewire を Lambda に載せられないか? -デプロイ方法は? -バッチ処理は? (Lambda は 15分の制限)</p> -<p>Lambda でコンテナイメージがサポートされるように</p> -<p>抽象化されたもの「だけ」しか知らないよりも具象の理解は助けになる</p> -</blockquote> -<p>AWS Lambda のような Function as a Service はマイクロサービス化における一つの到達点に思えるのだが、これを使って実際に web サービスを作る具体的なイメージがまだ見えない (注: すべて for me として書いている)。</p> -<p>PHP on AWS Lambda があれだけ簡単に動かせるのには驚いた。</p> -<p>勝手に AWS Lambda だとフットプリントの軽さが求められそう (= PHP + Laravel などでは動かなさそう) だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。</p> -<h3 id="1810-a">18:10 [A]</h3> -<p>大規模サイトの SEO</p> -<blockquote> -<p>大規模サイト (100万ページ以上) -Google の基準</p> -<p>クロールバジェットを意識したSEO</p> -<p>大規模サイトでコンテンツが中頻度 (1回/週) で更新 OR 中規模サイト (10,000以上) でコンテンツが目まぐるしく変更される -これを満たさないなら、クロールバジェットを考えなくてもいい</p> -<p>サーチコンソール -「カバレッジ」の「除外」 -多すぎるのは問題→クロールバジェットを浪費している</p> -<ul> -<li>クエリの順番を決める</li> -<li>空の値のルールを決めておく</li> -<li>リダイレクトすればインデックスはうまくいく</li> -<li>リンクが存在する限りクロールはされる</li> -</ul> -<p>リニューアル前のURL</p> -<p>インデックスは移行される -リンクのURLが存在する限り、別のURLとしてクロールされる -リダイレクトされるとはいえ、リニューアル前のURLは移行した方が良い -リニューアルで無視されるようになったパラメータも注意</p> -<p>robotes.txt で拒否しているのにクロールされる -一時的に拒否を外して 404 や 301 を読ませる -内部リンクを確認する -JS でのリンクに書き換え</p> -<p>クエリパラメータからURLのパスに -<code>/tokyo?area=HOGE</code> → <code>/tokyo/HOGE</code></p> -<p>URL 設計だいじ</p> -</blockquote> -<p>SEO (Search Engine Optimization) は大して知らないので新鮮な話が多かった。その分語れることも少ない……。</p> -<h3 id="1850-a">18:50 [A]</h3> -<blockquote> -<p>知覚可能 -操作可能 -理解可能 -堅牢 ちゃんとしたHTMLを書く (閉じタグ・入れ子構造など)</p> -<ul> -<li> -<p>標準の HTML を適切に使う</p> -</li> -<li> -<p>WAI-ARIA</p> -</li> -<li> -<p>キーボードフレンドリー</p> -</li> -<li> -<p>マシンフレンドリー</p> -</li> -<li> -<p>SEOフレンドリー</p> -</li> -</ul> -<p>button タグ -→キーボード -h1 タグ -→スクリーンリーダー・クローラ -a タグ</p> -<p>WAI-ARIA -HTML では表現できないセマンティクスを追加する</p> -<ul> -<li>ロール -<ul> -<li>何をするのか?</li> -<li>ユーザーアクションによって変化しない</li> -</ul> -</li> -<li>プロパティ -<ul> -<li>関連づけられたデータ</li> -</ul> -</li> -<li>ステート -<ul> -<li>現在の状態</li> -</ul> -</li> -</ul> -<p>まずは標準の HTML 要素で解決する -何でもかんでも WAI-ARIA を使えばいいというものではない</p> -<p>マウスホバーでツールチップが出てくるが、キーボード操作では出てこない</p> -<p>VoiceOver</p> -<p>全ての属性を使う必要はない -あくまでアクセシビリティを上げるための方法の一つにすぎない</p> -</blockquote> -<p>つい最近 WAI-ARIA についての記事を読んだばかりだったので個人的にタイムリーな話題だった。(あまりこの言葉を使いたくないのだが) いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。</p> -<h3 id="1930-a">19:30 [A]</h3> -<p>PHP で FUSE</p> -<p>個人的に楽しみだった発表。</p> -<blockquote> -<p>VFS (virtual filesystem) vs 具体的なファイルシステム</p> -<p>最適な実装方法は状況により異なる</p> -<p>アプリケーションに見せるAPIは変えずに実装を隠蔽する→VFS</p> -<p>カーネルのプログラムを作るのは難しい</p> -<ul> -<li>権限がデカすぎる</li> -<li>システム全体がクラッシュ</li> -<li>セキュリティリスク</li> -<li>開発サイクルを回しづらい</li> -<li>ネイティブコードにコンパイルされる言語である必要がある</li> -</ul> -<p>Filesystem in USEr space (FUSE)</p> -<ul> -<li>特定の C の関数を呼ぶことで filesystem が作れる</li> -<li>FFI を持つ言語なら FUSE が使える</li> -</ul> -<p>SSHFS / s3fs / Docker Desktop</p> -<p>Linux 以外でも使える</p> -<ul> -<li>dokany (on Windows)</li> -<li>osxfuse</li> -</ul> -<p>VFS: システムコールが呼ばれると、ファイルシステムによってコール -FUSE: カーネル空間からユーザ空間へ通信</p> -<p>高レベルなラッパで型をつける</p> -<p>PHP 以外では Wordpress を FUSE にマウントする実装がある (C, Python など)</p> -<ul> -<li>grep できる</li> -<li>sed できる</li> -<li>編集できる</li> -</ul> -</blockquote> -<p>期待通りの興味深い発表だった。FUSE 自体も今回の発表で知ったのだが、これ本体の実装を見るのも面白そうだ。 -この発表を聞きながらファイルシステムにマウントできそうなものを考えていたのだが、およそ木構造をしているものすべてと言えそうだ (ハンマーしか持っていないと云々)。何かできそうだがなかなか思いつかない。</p> -<h2 id="day-1-20210327">Day 1 (2021/03/27)</h2> -<h3 id="1050-a">10:50 [A]</h3> -<p>ATDD</p> -<blockquote> -<ul> -<li>ユーザーストーリー</li> -<li>ユニットテスト</li> -<li>CI/CD</li> -</ul> -<p>ユーザストーリーの受け入れ条件が曖昧になりがち -デグレチェックがユニットレベルでは収まらない場合、手動で同じシナリオをテストしている</p> -<p>Q2の強化 -アジャイルテストの4象限</p> -<p>技術面/ビジネス面 -開発チーム支援(コーディング前・コーディング中)/製品批評(コーディング後)</p> -<ul> -<li>Q1: 技術面 & チーム支援 -<ul> -<li>TDD</li> -<li>ユニットテストなど</li> -</ul> -</li> -<li>Q2: ビジネス面 & チーム支援 -<ul> -<li>ATDD</li> -<li>ビジネス面の受け入れテストで駆動する</li> -</ul> -</li> -</ul> -<p>Agile Alliance -ユーザストーリーのスキルレベルを高める</p> -<p>テストピラミッド</p> -<ul> -<li> -<p>UI Tests</p> -</li> -<li> -<p>Service Tests</p> -</li> -<li> -<p>Unit Tests</p> -</li> -<li> -<p>異なる粒度のテストを書く</p> -</li> -<li> -<p>高レベルになるほど、持つべきテストは少なくなる</p> -<ul> -<li>ピラミッド型になる</li> -</ul> -</li> -</ul> -<p>高レベルテストが多すぎる→アイスクリームコーン アンチパターン</p> -<p>ATDD (Acceptance TDD) -API経由・UI経由での高レベルテスト E2E test</p> -<p>ストーリ受け入れテスト</p> -<p>入れ子のフィードバックループ -ATDD(外側) と TDD(内側)</p> -<p>外部品質・内部品質</p> -<p>バーティカルスライスのデリバリー</p> -<ul> -<li>cucumber</li> -<li>gauge</li> -<li>behat</li> -</ul> -<p>ユビキタス言語 -手動テストもspecに書く -自動化は可能だがコスパが悪い -失敗することがわかっているテスト(レッドテスト)はCIから外す -失敗時の原因究明が難しい -饒舌なエラーメッセージ -状況のスナップショット</p> -<p>Continuous Testing</p> -</blockquote> -<p>User Acceptance Test (UAT) くらいの規模になると個人開発・趣味開発では触れない領域なので、大いに勉強になった。スライドに添付されている資料が相当に充実していたので、これを読むのが本番といった様相すら感じる。 -高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。</p> -<h3 id="1150-a">11:50 [A]</h3> -<p>型解析を用いたリファクタリング</p> -<p>型のある世界で生きてきた身として大いに楽しみにしていた発表。</p> -<blockquote> -<ul> -<li>PHPStan</li> -<li>Phan</li> -<li>Psalm</li> -</ul> -<p>autoload も認識できる -bootstrapFiles</p> -<p>編集箇所と利用箇所を CI でチェック -ルールレベルを徐々に引き上げていく -警告が多すぎると見落としてしまう・無視されやすくなる</p> -<p>型がついていないことによるエラーが多い</p> -<p>型よりも詳細な検査 <code>Util_Assert::min</code></p> -<p>SQL を静的解析 -placeholder の型付け</p> -<p>警告レベルを低いレベルから導入 -タイプヒントを積極的に書いていく -PHPStan の拡張を追加する</p> -</blockquote> -<p>昨今、動的型付き言語での型宣言・型アノテーション・型ヒントの導入が相次いでいる。長らく静的型付き言語を書いてきた私からすると、ようやく気づいたかといったところだが、ともかく型を導入する言語が増えてきた。 -今のプロジェクトでも新しく追加するコードには型をつけるよう努めているが、どうしても古いコードには型がついていない。個人的には型のないコードに対してどう型を自動的に付けるかという点に興味があり、その点で Ruby の typeprof には注目している。</p> -<h3 id="1230-a">12:30 [A]</h3> -<p>昼食をとっていた。事前に何か食料を買っておくべきだった。</p> -<h3 id="1310-a">13:10 [A]</h3> -<p>Documentation as Code</p> -<p>この発表も以前から非常に楽しみにしていた。</p> -<blockquote> -<p>開発開始までのオーバーヘッド -新規にチームにジョイン -担当範囲外の機能を理解 -オンボーディングのコスト</p> -<p>PHPerKaigi 2020 で発表あり</p> -<p>継続的にシステムの理解を助けるドキュメント</p> -<p>継続的ドキュメンテーション -システムとドキュメントの乖離</p> -<p>書いてあることが間違っている・足りない</p> -<ul> -<li>徐々にずれていく</li> -<li>システムの更新タイミングとドキュメントの更新タイミングに差がある</li> -</ul> -<p>システムとドキュメントは対応関係がある</p> -<ul> -<li>間違ったドキュメント</li> -<li>存在しないドキュメント</li> -</ul> -<p>システムとドキュメントの乖離を定量化する -継続的に -システムの更新に近いタイミングで ドキュメントを更新し続ける</p> -<p>Documentation as Code</p> -<p>コードと同じツールでドキュメントを書く</p> -<ul> -<li>issue tracker</li> -<li>vcs</li> -<li>plain text markup</li> -<li>automation</li> -</ul> -<p>開発者 -システム -ドキュメント -構造化データ -ソフトウェア</p> -<p>システムから構造化データを抽出する -PHPDoc -OpenAPI</p> -<p>ビュー 関心ごとに合わせてアーキテクチャを一つ以上の側面(断面)で説明する</p> -<p>ビューの単位でドキュメントに</p> -<p>スタックトレースからのドキュメント生成</p> -</blockquote> -<p>ドキュメントの管理は現プロジェクトでも課題と感じている。作られた当初は正しくても、実態と乖離していくのを止めるのは困難を極める。全体的に興味深い発表だったが、特にスタックトレースからのドキュメント生成というアイデアに惹かれるものを感じた。スタックトレースという実態と不可分な (乖離しない) 情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。</p> -<h3 id="1410-a">14:10 [A]</h3> -<p>cookie による session 管理</p> -<p>全体的に基本的な話だったので特に触れない。Cookie やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。</p> -<h3 id="1450-a">14:50 [A]</h3> -<p>PHP のエラーと例外</p> -<blockquote> -<p>エラー PHPエンジンがエラーを通知する -例外 プログラムが投げる</p> -<p>PHP7-8とエラー</p> -<p>PHPエンジンのエラーの一部が \Error に変換されるようになった -→ try-catch で捕捉できる</p> -<p>\Error は例外とは異なる</p> -<p>PHP8 でエラーレベルの引き上げ</p> -<ul> -<li>捕捉すべきもの -<ul> -<li>recoverable</li> -</ul> -</li> -<li>捕捉すべきでないもの -<ul> -<li>unrecoverable</li> -<li>開発時に対処できるもの</li> -</ul> -</li> -</ul> -<p>例外</p> -<ul> -<li>捕捉して事後処理</li> -<li>捕捉せず(or 捕捉した上で)さらに上に是非を問う</li> -</ul> -<p>開発段階で例外を把握し、ハンドリングを考えておく</p> -<p>\Throwable \Exception と \Error</p> -<p>\Error はキャッチすべきでない</p> -<ul> -<li> -<p>\Error</p> -<ul> -<li>本番で起きてはいけない</li> -</ul> -</li> -<li> -<p>\LogicException</p> -<ul> -<li>本番で起きてはいけない -→生じないのだから捕捉もしない</li> -</ul> -</li> -<li> -<p>\RuntimeException</p> -<ul> -<li>起こるかもしれないので本番環境でも考慮する</li> -</ul> -</li> -</ul> -<p>捕捉して対応するのではなく、未然に防ぐ</p> -<p>独自例外を使う -\Exception を投げてしまうと、 -catch (\Exception)せざるを得ない -→catch 範囲が広すぎる</p> -<p>SPL の例外を使う</p> -<p>例外翻訳 -上位のレイヤが下位のレイヤの例外を捕捉し、上位レイヤのAPIに「翻訳」する -下位レイヤの知識に依存させない</p> -<p>@throws -捕捉してほしい例外を書き連ねておく</p> -<p>呼び出しもとに負わせたい責任</p> -</blockquote> -<p>PHP を学んでいる途中の私としては、今まさに聞きたい発表だった (現時点で PHP を書き始めてから 4ヶ月ほどになる)。</p> -<p>個人的に例外やエラーを最もうまく扱っているのは Go、Swift、Rust、Haskell などのエラーを「値として」扱う言語だと思っている。try-catch は通常の処理フローを完全に壊してしまう上、構文としても重すぎる。値としてのエラー通知は C言語時代への回帰ともいえるが、その頃と異なるのはエラーを暗黙のうちに握り潰すことがないということだ。これらの言語は型を持っており、静的に検証ができる (C のそれはまともな型付けではない。念のため)。</p> -<p>PHP のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。</p> -<h3 id="1530-a">15:30 [A]</h3> -<p>Laravel のメール認証</p> -<p>Laravel の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。</p> -<h3 id="1610-a">16:10 [A]</h3> -<p>gRPC</p> -<blockquote> -<p>Unary RPCs -Server streaming RPCs -Client streaming RPCs -Bidirectional streaming RPCs</p> -<p>Protobuf</p> -<p>実装とAPIが乖離しにくい -自動生成 -複数言語でも相互に使える</p> -<p>マイクロサービスのサービス通信 -スマホアプリ -ゲームサーバ</p> -<p>PHP では?</p> -<p>PHP ではストリーミングが難しい -リクエストごとにプロセスが使い捨て</p> -<p>PHP ではgRPCのクライアントしか対応していない</p> -<p>gRPC-Web -ブラウザで扱うためのJSライブラリ+プロトコル</p> -<p>HTTP/1.1 でも使える -Unary RPC と Server streaming RPC のみ</p> -<p>Envoy -Nginx などで相互に gRPC と gRPC-Web で変換</p> -<p>Amp -イベント駆動な並行処理のフレームワーク</p> -<p>HTTP/2 対応</p> -<p>C#のgRPC-Webが楽</p> -</blockquote> -<p>(発表の中でもまさに同じことをおっしゃっていたが) PHP 以外の方が向いているだろう、というのが第一の感想である。gRPC はそれ自体というよりも Protobuf というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。</p> -<h3 id="1650-a">16:50 [A]</h3> -<p>アーキテクチャテスト</p> -<blockquote> -<p>Independent Core Layer Pattern</p> -<p>開発初期のアーキテクチャが崩れる -アーキテクチャ観点のコードレビューができない</p> -<p>どこにクラスを置けばよいか? -ドキュメントがない</p> -<p>アーキテクチャ設計に関する知識が属人化・暗黙知化</p> -<p>ガイドライン</p> -<ul> -<li>最初にルールを決めるのは簡単</li> -<li>ルール通り作り始めるのも簡単 -<ul> -<li>→維持するのが難しい、人が決めたものゆえ壊れやすい</li> -</ul> -</li> -</ul> -<p>PHP の特性</p> -<ul> -<li>クラスは public</li> -<li>可視性の制御が public / protected / private のみ</li> -<li>依存関係の制御が困難</li> -</ul> -<p>アーキテクチャテスト -クラスの依存関係や実装ルールをコードとして表現し、自動テスト化する</p> -<ul> -<li>deptrac</li> -<li>phpat</li> -</ul> -<p>Independent Core Layer Pattern</p> -<p>アーキテクチャテストの失敗</p> -<ul> -<li>実装誤り</li> -<li>or アーキテクチャが適切でない -<ul> -<li>開発の過程でフィードバックしていく</li> -</ul> -</li> -</ul> -<p>モジュラーモノリス→マイクロサービスへ</p> -</blockquote> -<h2 id="day-2-20210328">Day 2 (2021/03/28)</h2> -<p>冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。</p> -<p>残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。</p> -<h2 id="全体の感想">全体の感想</h2> -<p>Day 2 にほとんど参加できなかったのは残念だが、イベント自体は大変楽しく、また興味深いものであった。自分がまったく知らない領域の話を聞けるのはこうしたイベントならではだと感じる。オンライン開催ゆえ現地に行く必要がなく、気軽に参加できたのも (特に初参加者として) 嬉しいポイントだった。</p> -<p>今回、雑談/登壇者への質問等向けに Discord サーバもあったのだが、こちらは参加こそしたものの ROM のままになってしまった。発表に1ウィンドウ、メモを書くのに1ウィンドウ、Discord 表示に 1ウィンドウで私にはもう脳のリソースとディスプレイのスペースが追いつかなかった (さらにいうと Zoom でアンカンファレンスもやっていたようだ。こちらはまったく参加していない)。</p> -<p>1つ個人的な反省点としては、一つ一つのセッションを真剣に聞き過ぎたというものがある。もっと適当に聞いておけばよかった。これだけだと大変語弊があるのだが、言い方を変えると、Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。 -まあ初カンファレンスだし、とお茶を濁しておこう。</p> -<p>さて、カンファレンスで一つ気になったことがある。それは、Discord という書き込み場所が増えたことでニコ生のコメントの流量が吸い取られてしまったのではないか、という点だ。ニコニコだけ見ていると過疎っているかのように見えた発表も、Discord の方では盛り上がっている、というのを何度か見かけた。ニコニコのコメント方式は盛り上がりを如実に反映するが、逆もまたしかり。Discord があったこと自体はプラスだったと思うが、この点はマイナスだったのではないかと感じる。</p> -<hr> -<p>最後になりましたが、毎年の PHPerKaigi 開催にご尽力されている皆様、スピーカーの皆様、楽しい3日間でした。ありがとうございました! -(ずっと常体で書いてしまったのでいきなり仏頂面から笑顔になったようで気持ち悪い)</p> -<p>ではまた来年。</p> -]]></description> - </item> - - </channel> -</rss> diff --git a/docs/tags/phperkaigi/index.html b/docs/tags/phperkaigi/index.html deleted file mode 100644 index ac09c96..0000000 --- a/docs/tags/phperkaigi/index.html +++ /dev/null @@ -1,93 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - - <title>phperkaigi | REPL: Rest-Eat-Program Loop</title> - - <meta name="description" content=""> - <meta name="author" content="nsfisis"> - - <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet"> - - <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg"> - <meta name="generator" content="Hugo 0.102.1" /> - - <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/phperkaigi/feed.xml" title="REPL: Rest-Eat-Program Loop" /> - - </head> - <body class="list"> - <header class="header"> - <nav class="nav"> - <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p> - </nav> - </header> - <main class="main"> - -<header class="page-header"><h1>phperkaigi</h1></header> - -<article class="post-entry"> - <header class="entry-header"> - <h2>PHPerKaigi 2023: ボツになったトークン問題 その 1</h2> - </header> - <section class="entry-content"> - <p>来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、 -ボツになった問題を公開する (その 1)。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2022-10-23</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/"></a> -</article> -<article class="post-entry"> - <header class="entry-header"> - <h2>PHPerKaigi 2022</h2> - </header> - <section class="entry-content"> - <p>2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に参加した。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2022-05-01</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/"></a> -</article> -<article class="post-entry"> - <header class="entry-header"> - <h2>PHPerKaigi 2022 トークン問題の解説</h2> - </header> - <section class="entry-content"> - <p>PHPerKaigi 2022 で私が作成した PHPer チャレンジ問題を解説する。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2022-04-09</time>, updated on <time>2022-04-16</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/"></a> -</article> -<article class="post-entry"> - <header class="entry-header"> - <h2>PHPerKaigi 2021</h2> - </header> - <section class="entry-content"> - <p>2021-03-26 から 2021-03-28 にかけて開催された、PHPerKaigi 2021 に参加した。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2021-03-30</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/"></a> -</article></main> -<footer class="footer"> - <span>© 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span> - <span>·</span> - <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span> -</footer> -<script src="https://blog.nsfisis.dev/highlight.min.js"></script> -<script> - hljs.initHighlightingOnLoad(); -</script> -</body> -</html> - diff --git a/docs/tags/phperkaigi/page/1/index.html b/docs/tags/phperkaigi/page/1/index.html deleted file mode 100644 index 38c704d..0000000 --- a/docs/tags/phperkaigi/page/1/index.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <title>https://blog.nsfisis.dev/tags/phperkaigi/</title> - <link rel="canonical" href="https://blog.nsfisis.dev/tags/phperkaigi/"> - <meta name="robots" content="noindex"> - <meta charset="utf-8"> - <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/phperkaigi/"> - </head> -</html> diff --git a/docs/tags/python/feed.xml b/docs/tags/python/feed.xml deleted file mode 100644 index 3b8ba29..0000000 --- a/docs/tags/python/feed.xml +++ /dev/null @@ -1,57 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> - <channel> - <title>python on REPL: Rest-Eat-Program Loop</title> - <link>https://blog.nsfisis.dev/tags/python/</link> - <description>Recent content in python on REPL: Rest-Eat-Program Loop</description> - <generator>Hugo -- gohugo.io</generator> - <language>ja-JP</language> - <lastBuildDate>Sat, 02 Oct 2021 09:32:37 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/python/feed.xml" rel="self" type="application/rss+xml" /> - <item> - <title>[Python] クロージャとUnboundLocalError: local variable 'x' referenced before assignment</title> - <link>https://blog.nsfisis.dev/posts/2021-10-02/python-unbound-local-error/</link> - <pubDate>Sat, 02 Oct 2021 09:32:37 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2021-10-02/python-unbound-local-error/</guid> - <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。 -元 URL: <a href="https://qiita.com/nsfisis/items/5d733703afcb35bbf399">https://qiita.com/nsfisis/items/5d733703afcb35bbf399</a></p> -<hr> -<p>本記事は Python 3.7.6 の動作結果を元にして書かれている。</p> -<p>Python でクロージャを作ろうと、次のようなコードを書いた。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>(): -</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>(): -</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> g() -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>f() -</span></span></code></pre></div><p>関数 <code>g</code> から 関数 <code>f</code> のスコープ内で定義された変数 <code>x</code> を参照し、それに 1 を足そうとしている。 -これを実行すると <code>x += 1</code> の箇所でエラーが発生する。</p> -<blockquote> -<p>UnboundLocalError: local variable ‘x’ referenced before assignment</p> -</blockquote> -<p>local変数 <code>x</code> が代入前に参照された、とある。これは、<code>f</code> の <code>x</code> を参照するのではなく、新しく別の変数を <code>g</code> 内に作ってしまっているため。 -前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。<code>var</code> を変数宣言のための構文として擬似的に利用している。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#75715e"># 注: var は正しい Python の文法ではない。上記参照のこと</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>(): -</span></span><span style="display:flex;"><span> var x <span style="color:#75715e"># f の local変数 'x' を宣言</span> -</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> <span style="color:#75715e"># x に 0 を代入</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>(): <span style="color:#75715e"># f の内部関数 g を定義</span> -</span></span><span style="display:flex;"><span> var x <span style="color:#75715e"># g の local変数 'x' を宣言</span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># たまたま f にも同じ名前の変数があるが、それとは別の変数</span> -</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span> <span style="color:#75715e"># x に 1 を加算 (x = x + 1 の糖衣構文)</span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># 加算する前の値を参照しようとするが、まだ代入されていないためエラー</span> -</span></span><span style="display:flex;"><span> g() -</span></span></code></pre></div><p>当初の意図を表現するには、次のように書けばよい。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>(): -</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>(): -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">nonlocal</span> x <span style="color:#75715e">## (*)</span> -</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> g() -</span></span></code></pre></div><p><code>(*)</code> のように、<code>nonlocal</code> を追加する。これにより一つ外側のスコープ (<code>g</code> の一つ外側 = <code>f</code>) で定義されている <code>x</code> を探しに行くようになる。</p> -]]></description> - </item> - - </channel> -</rss> diff --git a/docs/tags/python/index.html b/docs/tags/python/index.html deleted file mode 100644 index 884872e..0000000 --- a/docs/tags/python/index.html +++ /dev/null @@ -1,56 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - - <title>python | REPL: Rest-Eat-Program Loop</title> - - <meta name="description" content=""> - <meta name="author" content="nsfisis"> - - <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet"> - - <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg"> - <meta name="generator" content="Hugo 0.102.1" /> - - <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/python/feed.xml" title="REPL: Rest-Eat-Program Loop" /> - - </head> - <body class="list"> - <header class="header"> - <nav class="nav"> - <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p> - </nav> - </header> - <main class="main"> - -<header class="page-header"><h1>python</h1></header> - -<article class="post-entry"> - <header class="entry-header"> - <h2>[Python] クロージャとUnboundLocalError: local variable 'x' referenced before assignment</h2> - </header> - <section class="entry-content"> - <p>Python における UnboundLocalError の理由と対処法。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2021-10-02</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/python-unbound-local-error/"></a> -</article></main> -<footer class="footer"> - <span>© 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span> - <span>·</span> - <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span> -</footer> -<script src="https://blog.nsfisis.dev/highlight.min.js"></script> -<script> - hljs.initHighlightingOnLoad(); -</script> -</body> -</html> - diff --git a/docs/tags/python/page/1/index.html b/docs/tags/python/page/1/index.html deleted file mode 100644 index ca045d7..0000000 --- a/docs/tags/python/page/1/index.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <title>https://blog.nsfisis.dev/tags/python/</title> - <link rel="canonical" href="https://blog.nsfisis.dev/tags/python/"> - <meta name="robots" content="noindex"> - <meta charset="utf-8"> - <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/python/"> - </head> -</html> diff --git a/docs/tags/python3/feed.xml b/docs/tags/python3/feed.xml deleted file mode 100644 index 260f94a..0000000 --- a/docs/tags/python3/feed.xml +++ /dev/null @@ -1,57 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> - <channel> - <title>python3 on REPL: Rest-Eat-Program Loop</title> - <link>https://blog.nsfisis.dev/tags/python3/</link> - <description>Recent content in python3 on REPL: Rest-Eat-Program Loop</description> - <generator>Hugo -- gohugo.io</generator> - <language>ja-JP</language> - <lastBuildDate>Sat, 02 Oct 2021 09:32:37 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/python3/feed.xml" rel="self" type="application/rss+xml" /> - <item> - <title>[Python] クロージャとUnboundLocalError: local variable 'x' referenced before assignment</title> - <link>https://blog.nsfisis.dev/posts/2021-10-02/python-unbound-local-error/</link> - <pubDate>Sat, 02 Oct 2021 09:32:37 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2021-10-02/python-unbound-local-error/</guid> - <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。 -元 URL: <a href="https://qiita.com/nsfisis/items/5d733703afcb35bbf399">https://qiita.com/nsfisis/items/5d733703afcb35bbf399</a></p> -<hr> -<p>本記事は Python 3.7.6 の動作結果を元にして書かれている。</p> -<p>Python でクロージャを作ろうと、次のようなコードを書いた。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>(): -</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>(): -</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> g() -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>f() -</span></span></code></pre></div><p>関数 <code>g</code> から 関数 <code>f</code> のスコープ内で定義された変数 <code>x</code> を参照し、それに 1 を足そうとしている。 -これを実行すると <code>x += 1</code> の箇所でエラーが発生する。</p> -<blockquote> -<p>UnboundLocalError: local variable ‘x’ referenced before assignment</p> -</blockquote> -<p>local変数 <code>x</code> が代入前に参照された、とある。これは、<code>f</code> の <code>x</code> を参照するのではなく、新しく別の変数を <code>g</code> 内に作ってしまっているため。 -前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。<code>var</code> を変数宣言のための構文として擬似的に利用している。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#75715e"># 注: var は正しい Python の文法ではない。上記参照のこと</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>(): -</span></span><span style="display:flex;"><span> var x <span style="color:#75715e"># f の local変数 'x' を宣言</span> -</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> <span style="color:#75715e"># x に 0 を代入</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>(): <span style="color:#75715e"># f の内部関数 g を定義</span> -</span></span><span style="display:flex;"><span> var x <span style="color:#75715e"># g の local変数 'x' を宣言</span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># たまたま f にも同じ名前の変数があるが、それとは別の変数</span> -</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span> <span style="color:#75715e"># x に 1 を加算 (x = x + 1 の糖衣構文)</span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># 加算する前の値を参照しようとするが、まだ代入されていないためエラー</span> -</span></span><span style="display:flex;"><span> g() -</span></span></code></pre></div><p>当初の意図を表現するには、次のように書けばよい。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>(): -</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>(): -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">nonlocal</span> x <span style="color:#75715e">## (*)</span> -</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> g() -</span></span></code></pre></div><p><code>(*)</code> のように、<code>nonlocal</code> を追加する。これにより一つ外側のスコープ (<code>g</code> の一つ外側 = <code>f</code>) で定義されている <code>x</code> を探しに行くようになる。</p> -]]></description> - </item> - - </channel> -</rss> diff --git a/docs/tags/python3/index.html b/docs/tags/python3/index.html deleted file mode 100644 index 5e18ffd..0000000 --- a/docs/tags/python3/index.html +++ /dev/null @@ -1,56 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - - <title>python3 | REPL: Rest-Eat-Program Loop</title> - - <meta name="description" content=""> - <meta name="author" content="nsfisis"> - - <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet"> - - <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg"> - <meta name="generator" content="Hugo 0.102.1" /> - - <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/python3/feed.xml" title="REPL: Rest-Eat-Program Loop" /> - - </head> - <body class="list"> - <header class="header"> - <nav class="nav"> - <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p> - </nav> - </header> - <main class="main"> - -<header class="page-header"><h1>python3</h1></header> - -<article class="post-entry"> - <header class="entry-header"> - <h2>[Python] クロージャとUnboundLocalError: local variable 'x' referenced before assignment</h2> - </header> - <section class="entry-content"> - <p>Python における UnboundLocalError の理由と対処法。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2021-10-02</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/python-unbound-local-error/"></a> -</article></main> -<footer class="footer"> - <span>© 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span> - <span>·</span> - <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span> -</footer> -<script src="https://blog.nsfisis.dev/highlight.min.js"></script> -<script> - hljs.initHighlightingOnLoad(); -</script> -</body> -</html> - diff --git a/docs/tags/python3/page/1/index.html b/docs/tags/python3/page/1/index.html deleted file mode 100644 index 1c8bbe3..0000000 --- a/docs/tags/python3/page/1/index.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <title>https://blog.nsfisis.dev/tags/python3/</title> - <link rel="canonical" href="https://blog.nsfisis.dev/tags/python3/"> - <meta name="robots" content="noindex"> - <meta charset="utf-8"> - <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/python3/"> - </head> -</html> diff --git a/docs/tags/ruby/feed.xml b/docs/tags/ruby/feed.xml deleted file mode 100644 index 50612e5..0000000 --- a/docs/tags/ruby/feed.xml +++ /dev/null @@ -1,230 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> - <channel> - <title>ruby on REPL: Rest-Eat-Program Loop</title> - <link>https://blog.nsfisis.dev/tags/ruby/</link> - <description>Recent content in ruby on REPL: Rest-Eat-Program Loop</description> - <generator>Hugo -- gohugo.io</generator> - <language>ja-JP</language> - <lastBuildDate>Sat, 02 Oct 2021 09:38:50 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/ruby/feed.xml" rel="self" type="application/rss+xml" /> - <item> - <title>[Ruby] then キーワードと case in</title> - <link>https://blog.nsfisis.dev/posts/2021-10-02/ruby-then-keyword-and-case-in/</link> - <pubDate>Sat, 02 Oct 2021 09:38:50 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2021-10-02/ruby-then-keyword-and-case-in/</guid> - <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。 -元 URL: <a href="https://qiita.com/nsfisis/items/787a8cf888a304497223">https://qiita.com/nsfisis/items/787a8cf888a304497223</a></p> -<hr> -<h1 id="tl-dr">TL; DR</h1> -<p><code>case</code> - <code>in</code> によるパターンマッチング構文でも、<code>case</code> - <code>when</code> と同じように <code>then</code> が使える (場合によっては使う必要がある)。</p> -<h1 id="then-とは"><code>then</code> とは</h1> -<p>使われることは稀だが、Ruby では <code>then</code> がキーワードになっている。次のように使う:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> cond <span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> puts <span style="color:#e6db74">"Y"</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span> -</span></span><span style="display:flex;"><span> puts <span style="color:#e6db74">"N"</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span></code></pre></div><p>このキーワードが現れうる場所はいくつかあり、<code>if</code>、<code>unless</code>、<code>rescue</code>、<code>case</code> 構文がそれに当たる。 -上記のように、何か条件を書いた後 <code>then</code> を置き、式がそこで終了していることを示すマーカーとして機能する。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># Example:</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> x <span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> a -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">unless</span> x <span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> a -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">begin</span> -</span></span><span style="display:flex;"><span> a -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">rescue</span> <span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> b -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">when</span> p <span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> a -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span></code></pre></div><h1 id="なぜ普段は書かなくてもよいのか">なぜ普段は書かなくてもよいのか</h1> -<p>普通 Ruby のコードで <code>then</code> を書くことはない。なぜか。次のコードを実行してみるとわかる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#66d9ef">true</span> puts <span style="color:#e6db74">'Hello, World!'</span> <span style="color:#66d9ef">end</span> -</span></span></code></pre></div><p>次のような構文エラーが出力される。</p> -<pre tabindex="0"><code>20:1: syntax error, unexpected local variable or method, expecting `then' or ';' or '\n' -if true puts 'Hello, World!' end - ^~~~ -20:1: syntax error, unexpected `end', expecting end-of-input -...f true puts 'Hello, World!' end -</code></pre><p>二つ目のメッセージは無視して一つ目を読むと、<code>then</code> か <code>;</code> か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。</p> -<p>ポイントは改行が <code>then</code> (や <code>;</code>) の代わりとなることである。<code>true</code> の後に改行を入れてみる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span>puts <span style="color:#e6db74">'Hello, World!'</span> <span style="color:#66d9ef">end</span> -</span></span></code></pre></div><p>無事 Hello, World! と出力されるようになった。</p> -<h1 id="なぜ-then-や--や改行が必要か">なぜ <code>then</code> や <code>;</code> や改行が必要か</h1> -<p>なぜ <code>then</code> や <code>;</code> や改行 (以下 「<code>then</code> 等」) が必要なのだろうか。次の例を見てほしい:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a b <span style="color:#66d9ef">end</span> -</span></span></code></pre></div><p><code>then</code> も <code>;</code> も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。 -この例は二通りに解釈できる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a <span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> b -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># その結果が truthy なら何もしない</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a(b) <span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span></code></pre></div><p><code>then</code> 等はこの曖昧性を排除するためにあり、条件式は <code>if</code> から <code>then</code> 等までの間にある、ということを明確にする。 -C系の <code>if</code> 後に来る <code>(</code>/<code>)</code> や、Python の <code>:</code>、Rust/Go/Swift などの <code>{</code> も同じ役割を持つ。</p> -<p>Ruby の場合、プログラマーが書きやすいよう改行でもって <code>then</code> が代用できるので、ほとんどの場合 <code>then</code> は必要ない。</p> -<h1 id="case---in-における-then"><code>case</code> - <code>in</code> における <code>then</code></h1> -<p>ようやく本題にたどり着いた。来る Ruby 3.0 では <code>case</code> と <code>in</code> キーワードを使ったパターンマッチングの構文が入る予定である。この構文でもパターン部との区切りとして <code>then</code> 等が必要になる。 -(現在の) Ruby には formal な形式での文法仕様は存在しないので、yacc の定義ファイルを参照した (yacc の説明は省略)。</p> -<p><a href="https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986">https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986</a></p> -<pre tabindex="0"><code class="language-yacc" data-lang="yacc">p_case_body : keyword_in - { - SET_LEX_STATE(EXPR_BEG|EXPR_LABEL); - p->command_start = FALSE; - $<ctxt>1 = p->ctxt; - p->ctxt.in_kwarg = 1; - $<tbl>$ = push_pvtbl(p); - } - { - $<tbl>$ = push_pktbl(p); - } - p_top_expr then - { - pop_pktbl(p, $<tbl>3); - pop_pvtbl(p, $<tbl>2); - p->ctxt.in_kwarg = $<ctxt>1.in_kwarg; - } - compstmt - p_cases - { - /*%%%*/ - $$ = NEW_IN($4, $7, $8, &@$); - /*% %*/ - /*% ripper: in!($4, $7, escape_Qundef($8)) %*/ - } - ; -</code></pre><p>簡略版:</p> -<pre tabindex="0"><code class="language-yacc" data-lang="yacc">p_case_body : keyword_in p_top_expr then compstmt p_cases - ; -</code></pre><p>ここで、<code>keyword_in</code> は文字通り <code>in</code>、<code>p_top_expr</code> はいわゆるパターン、<code>then</code> は <code>then</code> キーワードのことではなく、この記事で <code>then</code> 等と呼んでいるもの、つまり <code>then</code> キーワード、<code>;</code>、改行のいずれかである。</p> -<p>これにより、<code>case</code> - <code>when</code> による従来の構文と同じように、<code>then</code> 等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span> <span style="color:#66d9ef">then</span> a -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span> <span style="color:#66d9ef">then</span> b -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span> <span style="color:#66d9ef">then</span> c -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> a -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span> b -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span> c -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span>; a -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span>; b -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span>; c -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span></code></pre></div><p>ところで、<code>p_top_expr</code> には <code>if</code> による guard clause が書けるので、その場合は <code>if</code> - <code>then</code> と似たような見た目になる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">0</span> <span style="color:#66d9ef">then</span> a -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> n <span style="color:#66d9ef">if</span> n <span style="color:#f92672"><</span> <span style="color:#ae81ff">0</span> <span style="color:#66d9ef">then</span> b -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> n <span style="color:#66d9ef">then</span> c -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span></code></pre></div><h1 id="まとめ">まとめ</h1> -<ul> -<li><code>if</code> や <code>case</code> の条件の後ろには <code>then</code>、<code>;</code>、改行のいずれかが必要 -<ul> -<li>通常は改行しておけばよい</li> -</ul> -</li> -<li>3.0 で入る予定の <code>case</code> - <code>in</code> でも <code>then</code> 等が必要になる</li> -<li>Ruby の構文を正確に知るには (現状) <code>parse.y</code> を直接読めばよい</li> -</ul> -]]></description> - </item> - - <item> - <title>[Ruby] 自身を実行している処理系の種類を判定する</title> - <link>https://blog.nsfisis.dev/posts/2021-10-02/ruby-detect-running-implementation/</link> - <pubDate>Sat, 02 Oct 2021 09:37:50 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2021-10-02/ruby-detect-running-implementation/</guid> - <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。 -元 URL: <a href="https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791">https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791</a></p> -<hr> -<p>Ruby という言語には複数の実装があるが、それらをスクリプト上からどのようにして programmatically に見分ければよいだろうか。</p> -<p><code>Object</code> クラスに定義されている <code>RUBY_ENGINE</code> という定数がこの用途に使える。</p> -<p>参考: <a href="https://docs.ruby-lang.org/ja/latest/method/Object/c/RUBY_ENGINE.html">Object::RUBY_ENGINE</a></p> -<p>上記ページの例から引用する:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ ruby-1.9.1 -ve <span style="color:#e6db74">'p RUBY_ENGINE'</span> -</span></span><span style="display:flex;"><span>ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux] -</span></span><span style="display:flex;"><span>"ruby" -</span></span><span style="display:flex;"><span>$ jruby -ve <span style="color:#e6db74">'p RUBY_ENGINE'</span> -</span></span><span style="display:flex;"><span>jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java] -</span></span><span style="display:flex;"><span>"jruby" -</span></span></code></pre></div><p>それぞれの処理系がどのような値を返すかだが、stack overflow に良い質問と回答があった。</p> -<p><a href="https://stackoverflow.com/a/9894232">What values for RUBY_ENGINE correspond to which Ruby implementations?</a> より引用:</p> -<blockquote> -<table> -<thead> -<tr> -<th style="text-align:center">RUBY_ENGINE</th> -<th style="text-align:left">Implementation</th> -</tr> -</thead> -<tbody> -<tr> -<td style="text-align:center"><undefined></td> -<td style="text-align:left">MRI < 1.9</td> -</tr> -<tr> -<td style="text-align:center">‘ruby’</td> -<td style="text-align:left">MRI >= 1.9 or REE</td> -</tr> -<tr> -<td style="text-align:center">‘jruby’</td> -<td style="text-align:left">JRuby</td> -</tr> -<tr> -<td style="text-align:center">‘macruby’</td> -<td style="text-align:left">MacRuby</td> -</tr> -<tr> -<td style="text-align:center">‘rbx’</td> -<td style="text-align:left">Rubinius</td> -</tr> -<tr> -<td style="text-align:center">‘maglev’</td> -<td style="text-align:left">MagLev</td> -</tr> -<tr> -<td style="text-align:center">‘ironruby’</td> -<td style="text-align:left">IronRuby</td> -</tr> -<tr> -<td style="text-align:center">‘cardinal’</td> -<td style="text-align:left">Cardinal</td> -</tr> -</tbody> -</table> -</blockquote> -<p>なお、この質問・回答は 2014年になされたものであり、値は変わっている可能性がある。MRI (aka CRuby) については執筆時現在 (2020/12/8) も <code>'ruby'</code> が返ってくることを確認済み。</p> -<p>この表にない主要な処理系として、<a href="https://mruby.org">mruby</a> は <code>'mruby'</code> を返す。</p> -<p><a href="https://github.com/mruby/mruby/blob/ed29d74bfd95362eaeb946fcf7e865d80346b62b/include/mruby/version.h#L32-L35">mruby 該当部分のソース</a> より引用:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> * Ruby engine. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">#define MRUBY_RUBY_ENGINE "mruby" -</span></span></span></code></pre></div>]]></description> - </item> - - </channel> -</rss> diff --git a/docs/tags/ruby/index.html b/docs/tags/ruby/index.html deleted file mode 100644 index a23cbbf..0000000 --- a/docs/tags/ruby/index.html +++ /dev/null @@ -1,68 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - - <title>ruby | REPL: Rest-Eat-Program Loop</title> - - <meta name="description" content=""> - <meta name="author" content="nsfisis"> - - <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet"> - - <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg"> - <meta name="generator" content="Hugo 0.102.1" /> - - <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/ruby/feed.xml" title="REPL: Rest-Eat-Program Loop" /> - - </head> - <body class="list"> - <header class="header"> - <nav class="nav"> - <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p> - </nav> - </header> - <main class="main"> - -<header class="page-header"><h1>ruby</h1></header> - -<article class="post-entry"> - <header class="entry-header"> - <h2>[Ruby] then キーワードと case in</h2> - </header> - <section class="entry-content"> - <p>Ruby 3.0 で追加される case in 構文と、then キーワードについて。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2021-10-02</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/ruby-then-keyword-and-case-in/"></a> -</article> -<article class="post-entry"> - <header class="entry-header"> - <h2>[Ruby] 自身を実行している処理系の種類を判定する</h2> - </header> - <section class="entry-content"> - <p>Ruby には複数の実装があるが、自身を実行している処理系の種類をスクリプト上からどのように判定すればよいだろうか。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2021-10-02</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/ruby-detect-running-implementation/"></a> -</article></main> -<footer class="footer"> - <span>© 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span> - <span>·</span> - <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span> -</footer> -<script src="https://blog.nsfisis.dev/highlight.min.js"></script> -<script> - hljs.initHighlightingOnLoad(); -</script> -</body> -</html> - diff --git a/docs/tags/ruby/page/1/index.html b/docs/tags/ruby/page/1/index.html deleted file mode 100644 index 9374bc8..0000000 --- a/docs/tags/ruby/page/1/index.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <title>https://blog.nsfisis.dev/tags/ruby/</title> - <link rel="canonical" href="https://blog.nsfisis.dev/tags/ruby/"> - <meta name="robots" content="noindex"> - <meta charset="utf-8"> - <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/ruby/"> - </head> -</html> diff --git a/docs/tags/ruby3/feed.xml b/docs/tags/ruby3/feed.xml deleted file mode 100644 index 530cc62..0000000 --- a/docs/tags/ruby3/feed.xml +++ /dev/null @@ -1,155 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> - <channel> - <title>ruby3 on REPL: Rest-Eat-Program Loop</title> - <link>https://blog.nsfisis.dev/tags/ruby3/</link> - <description>Recent content in ruby3 on REPL: Rest-Eat-Program Loop</description> - <generator>Hugo -- gohugo.io</generator> - <language>ja-JP</language> - <lastBuildDate>Sat, 02 Oct 2021 09:38:50 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/ruby3/feed.xml" rel="self" type="application/rss+xml" /> - <item> - <title>[Ruby] then キーワードと case in</title> - <link>https://blog.nsfisis.dev/posts/2021-10-02/ruby-then-keyword-and-case-in/</link> - <pubDate>Sat, 02 Oct 2021 09:38:50 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2021-10-02/ruby-then-keyword-and-case-in/</guid> - <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。 -元 URL: <a href="https://qiita.com/nsfisis/items/787a8cf888a304497223">https://qiita.com/nsfisis/items/787a8cf888a304497223</a></p> -<hr> -<h1 id="tl-dr">TL; DR</h1> -<p><code>case</code> - <code>in</code> によるパターンマッチング構文でも、<code>case</code> - <code>when</code> と同じように <code>then</code> が使える (場合によっては使う必要がある)。</p> -<h1 id="then-とは"><code>then</code> とは</h1> -<p>使われることは稀だが、Ruby では <code>then</code> がキーワードになっている。次のように使う:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> cond <span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> puts <span style="color:#e6db74">"Y"</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span> -</span></span><span style="display:flex;"><span> puts <span style="color:#e6db74">"N"</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span></code></pre></div><p>このキーワードが現れうる場所はいくつかあり、<code>if</code>、<code>unless</code>、<code>rescue</code>、<code>case</code> 構文がそれに当たる。 -上記のように、何か条件を書いた後 <code>then</code> を置き、式がそこで終了していることを示すマーカーとして機能する。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># Example:</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> x <span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> a -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">unless</span> x <span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> a -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">begin</span> -</span></span><span style="display:flex;"><span> a -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">rescue</span> <span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> b -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">when</span> p <span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> a -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span></code></pre></div><h1 id="なぜ普段は書かなくてもよいのか">なぜ普段は書かなくてもよいのか</h1> -<p>普通 Ruby のコードで <code>then</code> を書くことはない。なぜか。次のコードを実行してみるとわかる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#66d9ef">true</span> puts <span style="color:#e6db74">'Hello, World!'</span> <span style="color:#66d9ef">end</span> -</span></span></code></pre></div><p>次のような構文エラーが出力される。</p> -<pre tabindex="0"><code>20:1: syntax error, unexpected local variable or method, expecting `then' or ';' or '\n' -if true puts 'Hello, World!' end - ^~~~ -20:1: syntax error, unexpected `end', expecting end-of-input -...f true puts 'Hello, World!' end -</code></pre><p>二つ目のメッセージは無視して一つ目を読むと、<code>then</code> か <code>;</code> か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。</p> -<p>ポイントは改行が <code>then</code> (や <code>;</code>) の代わりとなることである。<code>true</code> の後に改行を入れてみる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span>puts <span style="color:#e6db74">'Hello, World!'</span> <span style="color:#66d9ef">end</span> -</span></span></code></pre></div><p>無事 Hello, World! と出力されるようになった。</p> -<h1 id="なぜ-then-や--や改行が必要か">なぜ <code>then</code> や <code>;</code> や改行が必要か</h1> -<p>なぜ <code>then</code> や <code>;</code> や改行 (以下 「<code>then</code> 等」) が必要なのだろうか。次の例を見てほしい:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a b <span style="color:#66d9ef">end</span> -</span></span></code></pre></div><p><code>then</code> も <code>;</code> も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。 -この例は二通りに解釈できる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a <span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> b -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># その結果が truthy なら何もしない</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a(b) <span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span></code></pre></div><p><code>then</code> 等はこの曖昧性を排除するためにあり、条件式は <code>if</code> から <code>then</code> 等までの間にある、ということを明確にする。 -C系の <code>if</code> 後に来る <code>(</code>/<code>)</code> や、Python の <code>:</code>、Rust/Go/Swift などの <code>{</code> も同じ役割を持つ。</p> -<p>Ruby の場合、プログラマーが書きやすいよう改行でもって <code>then</code> が代用できるので、ほとんどの場合 <code>then</code> は必要ない。</p> -<h1 id="case---in-における-then"><code>case</code> - <code>in</code> における <code>then</code></h1> -<p>ようやく本題にたどり着いた。来る Ruby 3.0 では <code>case</code> と <code>in</code> キーワードを使ったパターンマッチングの構文が入る予定である。この構文でもパターン部との区切りとして <code>then</code> 等が必要になる。 -(現在の) Ruby には formal な形式での文法仕様は存在しないので、yacc の定義ファイルを参照した (yacc の説明は省略)。</p> -<p><a href="https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986">https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986</a></p> -<pre tabindex="0"><code class="language-yacc" data-lang="yacc">p_case_body : keyword_in - { - SET_LEX_STATE(EXPR_BEG|EXPR_LABEL); - p->command_start = FALSE; - $<ctxt>1 = p->ctxt; - p->ctxt.in_kwarg = 1; - $<tbl>$ = push_pvtbl(p); - } - { - $<tbl>$ = push_pktbl(p); - } - p_top_expr then - { - pop_pktbl(p, $<tbl>3); - pop_pvtbl(p, $<tbl>2); - p->ctxt.in_kwarg = $<ctxt>1.in_kwarg; - } - compstmt - p_cases - { - /*%%%*/ - $$ = NEW_IN($4, $7, $8, &@$); - /*% %*/ - /*% ripper: in!($4, $7, escape_Qundef($8)) %*/ - } - ; -</code></pre><p>簡略版:</p> -<pre tabindex="0"><code class="language-yacc" data-lang="yacc">p_case_body : keyword_in p_top_expr then compstmt p_cases - ; -</code></pre><p>ここで、<code>keyword_in</code> は文字通り <code>in</code>、<code>p_top_expr</code> はいわゆるパターン、<code>then</code> は <code>then</code> キーワードのことではなく、この記事で <code>then</code> 等と呼んでいるもの、つまり <code>then</code> キーワード、<code>;</code>、改行のいずれかである。</p> -<p>これにより、<code>case</code> - <code>when</code> による従来の構文と同じように、<code>then</code> 等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span> <span style="color:#66d9ef">then</span> a -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span> <span style="color:#66d9ef">then</span> b -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span> <span style="color:#66d9ef">then</span> c -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> a -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span> b -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span> c -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span>; a -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span>; b -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span>; c -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span></code></pre></div><p>ところで、<code>p_top_expr</code> には <code>if</code> による guard clause が書けるので、その場合は <code>if</code> - <code>then</code> と似たような見た目になる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">0</span> <span style="color:#66d9ef">then</span> a -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> n <span style="color:#66d9ef">if</span> n <span style="color:#f92672"><</span> <span style="color:#ae81ff">0</span> <span style="color:#66d9ef">then</span> b -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> n <span style="color:#66d9ef">then</span> c -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span> -</span></span></code></pre></div><h1 id="まとめ">まとめ</h1> -<ul> -<li><code>if</code> や <code>case</code> の条件の後ろには <code>then</code>、<code>;</code>、改行のいずれかが必要 -<ul> -<li>通常は改行しておけばよい</li> -</ul> -</li> -<li>3.0 で入る予定の <code>case</code> - <code>in</code> でも <code>then</code> 等が必要になる</li> -<li>Ruby の構文を正確に知るには (現状) <code>parse.y</code> を直接読めばよい</li> -</ul> -]]></description> - </item> - - </channel> -</rss> diff --git a/docs/tags/ruby3/index.html b/docs/tags/ruby3/index.html deleted file mode 100644 index b204a64..0000000 --- a/docs/tags/ruby3/index.html +++ /dev/null @@ -1,56 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - - <title>ruby3 | REPL: Rest-Eat-Program Loop</title> - - <meta name="description" content=""> - <meta name="author" content="nsfisis"> - - <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet"> - - <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg"> - <meta name="generator" content="Hugo 0.102.1" /> - - <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/ruby3/feed.xml" title="REPL: Rest-Eat-Program Loop" /> - - </head> - <body class="list"> - <header class="header"> - <nav class="nav"> - <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p> - </nav> - </header> - <main class="main"> - -<header class="page-header"><h1>ruby3</h1></header> - -<article class="post-entry"> - <header class="entry-header"> - <h2>[Ruby] then キーワードと case in</h2> - </header> - <section class="entry-content"> - <p>Ruby 3.0 で追加される case in 構文と、then キーワードについて。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2021-10-02</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/ruby-then-keyword-and-case-in/"></a> -</article></main> -<footer class="footer"> - <span>© 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span> - <span>·</span> - <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span> -</footer> -<script src="https://blog.nsfisis.dev/highlight.min.js"></script> -<script> - hljs.initHighlightingOnLoad(); -</script> -</body> -</html> - diff --git a/docs/tags/ruby3/page/1/index.html b/docs/tags/ruby3/page/1/index.html deleted file mode 100644 index 15caf8a..0000000 --- a/docs/tags/ruby3/page/1/index.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <title>https://blog.nsfisis.dev/tags/ruby3/</title> - <link rel="canonical" href="https://blog.nsfisis.dev/tags/ruby3/"> - <meta name="robots" content="noindex"> - <meta charset="utf-8"> - <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/ruby3/"> - </head> -</html> diff --git a/docs/tags/rust/feed.xml b/docs/tags/rust/feed.xml deleted file mode 100644 index 60f98d3..0000000 --- a/docs/tags/rust/feed.xml +++ /dev/null @@ -1,143 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> - <channel> - <title>rust on REPL: Rest-Eat-Program Loop</title> - <link>https://blog.nsfisis.dev/tags/rust/</link> - <description>Recent content in rust on REPL: Rest-Eat-Program Loop</description> - <generator>Hugo -- gohugo.io</generator> - <language>ja-JP</language> - <lastBuildDate>Sat, 02 Oct 2021 09:39:27 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/rust/feed.xml" rel="self" type="application/rss+xml" /> - <item> - <title>Rust のプリミティブ型はどこからやって来るか</title> - <link>https://blog.nsfisis.dev/posts/2021-10-02/rust-where-are-primitive-types-from/</link> - <pubDate>Sat, 02 Oct 2021 09:39:27 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2021-10-02/rust-where-are-primitive-types-from/</guid> - <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。 -元 URL: <a href="https://qiita.com/nsfisis/items/9a429432258bbcd6c565">https://qiita.com/nsfisis/items/9a429432258bbcd6c565</a></p> -<hr> -<h1 id="前置き">前置き</h1> -<p>Rust において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#75715e">#![allow(non_camel_case_types)]</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">#![allow(dead_code)]</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">bool</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">char</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i8</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i16</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i32</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i64</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i128</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">isize</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u8</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u16</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u32</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u64</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u128</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">usize</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">f32</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">f64</span>; -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">str</span>; -</span></span></code></pre></div><p>では、普段単に <code>bool</code> と書いたとき、この <code>bool</code> は一体どこから来ているのか。rustc のソースを追ってみた。</p> -<blockquote> -<p>前提知識: 一般的なコンパイラの構造、用語。<code>rustc</code> そのものの知識は不要 (というよりも筆者自身がよく知らない)</p> -</blockquote> -<h1 id="調査">調査</h1> -<p>調査に使用したソース (調査時点での最新 master)</p> -<p><a href="https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98">https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98</a></p> -<p>どのようにして調べるか。rustc の構造には詳しくないため、すぐに当たりをつけるのは難しい。</p> -<p>大雑把な構造としては、<code>compiler</code> フォルダ以下に <code>rustc_*</code> という名前のクレートが数十個入っている。これがどうやら <code>rustc</code> コマンドの実装部のようだ。</p> -<p><code>rustc</code> はセルフホストされている (= <code>rustc</code> 自身が Rust で書かれている) ので、<code>bool</code> や <code>char</code> などで適当に検索をかけてもノイズが多すぎて話にならない。 -しかし、お誂え向きなことに <code>i128</code>/<code>u128</code> というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って <code>git grep</code> してみる。</p> -<pre tabindex="0"><code>$ git grep "\bi128\b" | wc # i128 - 165 1069 15790 - -$ git grep "\bu128\b" | wc # u128 - 293 2127 26667 - -$ git grep "\bbool\b" | wc # cf. bool の結果 - 3563 23577 294659 -</code></pre><p>165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。</p> -<pre tabindex="0"><code>$ git grep "\bi128\b" -... -rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128)); -... -</code></pre><p><code>rustc_resolve</code> というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#e6db74">/// Interns the names of the primitive types. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">/// -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">/// All other types are defined somewhere and possibly imported, but the primitive ones need -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">/// special handling, since they have no place of origin. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">PrimitiveTypeTable</span> { -</span></span><span style="display:flex;"><span> primitive_types: <span style="color:#a6e22e">FxHashMap</span><span style="color:#f92672"><</span>Symbol, PrimTy<span style="color:#f92672">></span>, -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">impl</span> PrimitiveTypeTable { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">new</span>() -> <span style="color:#a6e22e">PrimitiveTypeTable</span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> table <span style="color:#f92672">=</span> FxHashMap::default(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">bool</span>, Bool); -</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">char</span>, Char); -</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">f32</span>, Float(FloatTy::F32)); -</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">f64</span>, Float(FloatTy::F64)); -</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">isize</span>, Int(IntTy::Isize)); -</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i8</span>, Int(IntTy::I8)); -</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i16</span>, Int(IntTy::I16)); -</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i32</span>, Int(IntTy::I32)); -</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i64</span>, Int(IntTy::I64)); -</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i128</span>, Int(IntTy::I128)); -</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">str</span>, Str); -</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">usize</span>, Uint(UintTy::Usize)); -</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u8</span>, Uint(UintTy::U8)); -</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u16</span>, Uint(UintTy::U16)); -</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u32</span>, Uint(UintTy::U32)); -</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u64</span>, Uint(UintTy::U64)); -</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u128</span>, Uint(UintTy::U128)); -</span></span><span style="display:flex;"><span> Self { primitive_types: <span style="color:#a6e22e">table</span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>これは初めに列挙したプリミティブ型の一覧と一致している。doc comment にも、</p> -<blockquote> -<p>All other types are defined somewhere and possibly imported, but the primitive ones need special handling, since they have no place of origin.</p> -</blockquote> -<p>とある。次はこの struct の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span> <span style="color:#e6db74">/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span> <span style="color:#e6db74">/// (略) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span> <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">resolve_ident_in_lexical_scope</span>( -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&</span><span style="color:#66d9ef">mut</span> self, -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">mut</span> ident: <span style="color:#a6e22e">Ident</span>, -</span></span><span style="display:flex;"><span> ns: <span style="color:#a6e22e">Namespace</span>, -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// (略) -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> ) -> Option<span style="color:#f92672"><</span>LexicalScopeBinding<span style="color:#f92672"><'</span><span style="color:#a6e22e">a</span><span style="color:#f92672">>></span> { -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// (略) -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> ns <span style="color:#f92672">==</span> TypeNS { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">let</span> Some(prim_ty) <span style="color:#f92672">=</span> self.primitive_type_table.primitive_types.get(<span style="color:#f92672">&</span>ident.name) { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> binding <span style="color:#f92672">=</span> -</span></span><span style="display:flex;"><span> (Res::PrimTy(<span style="color:#f92672">*</span>prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root()) -</span></span><span style="display:flex;"><span> .to_name_binding(self.arenas); -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> Some(LexicalScopeBinding::Item(binding)); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> None -</span></span><span style="display:flex;"><span> } -</span></span></code></pre></div><p>関数名や doc comment が示している通り、この関数は識別子 (identifier, ident) を現在のレキシカルスコープ内で解決 (resolve) する。 -<code>if ns == TypeNS</code> のブロック内では、<code>primitive_type_table</code> (上記の <code>PrimitiveTypeTable::new()</code> で作られた変数) に含まれている識別子 (<code>bool</code>、<code>i32</code> など) かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。</p> -<p>なお、<code>ns</code> は「名前空間」を示す変数である。Rust における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。この <code>if</code> は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。</p> -<p>重要なのは、これが <code>resolve_ident_in_lexical_scope()</code> の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。</p> -<p>動作がわかったところで、例として次のコードを考える。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#75715e">#![allow(non_camel_case_types)]</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">bool</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">main</span>() { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> _: <span style="color:#66d9ef">bool</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">bool</span>; -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>ここで <code>main()</code> の <code>bool</code> は <code>struct bool</code> として解決される。なぜなら、プリミティブ型の判定をする前に <code>bool</code> という名前の別の型が見つかるからだ。</p> -<h1 id="まとめ">まとめ</h1> -<p>Rust のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。</p> -]]></description> - </item> - - </channel> -</rss> diff --git a/docs/tags/rust/index.html b/docs/tags/rust/index.html deleted file mode 100644 index 7b89cc4..0000000 --- a/docs/tags/rust/index.html +++ /dev/null @@ -1,56 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - - <title>rust | REPL: Rest-Eat-Program Loop</title> - - <meta name="description" content=""> - <meta name="author" content="nsfisis"> - - <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet"> - - <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg"> - <meta name="generator" content="Hugo 0.102.1" /> - - <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/rust/feed.xml" title="REPL: Rest-Eat-Program Loop" /> - - </head> - <body class="list"> - <header class="header"> - <nav class="nav"> - <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p> - </nav> - </header> - <main class="main"> - -<header class="page-header"><h1>rust</h1></header> - -<article class="post-entry"> - <header class="entry-header"> - <h2>Rust のプリミティブ型はどこからやって来るか</h2> - </header> - <section class="entry-content"> - <p>Rust のプリミティブ型は予約語ではなく普通の識別子である。どのようにこれが名前解決されるのかを調べた。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2021-10-02</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/rust-where-are-primitive-types-from/"></a> -</article></main> -<footer class="footer"> - <span>© 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span> - <span>·</span> - <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span> -</footer> -<script src="https://blog.nsfisis.dev/highlight.min.js"></script> -<script> - hljs.initHighlightingOnLoad(); -</script> -</body> -</html> - diff --git a/docs/tags/rust/page/1/index.html b/docs/tags/rust/page/1/index.html deleted file mode 100644 index 5cf7d43..0000000 --- a/docs/tags/rust/page/1/index.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <title>https://blog.nsfisis.dev/tags/rust/</title> - <link rel="canonical" href="https://blog.nsfisis.dev/tags/rust/"> - <meta name="robots" content="noindex"> - <meta charset="utf-8"> - <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/rust/"> - </head> -</html> diff --git a/docs/tags/vim/feed.xml b/docs/tags/vim/feed.xml deleted file mode 100644 index 73bb677..0000000 --- a/docs/tags/vim/feed.xml +++ /dev/null @@ -1,191 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> - <channel> - <title>vim on REPL: Rest-Eat-Program Loop</title> - <link>https://blog.nsfisis.dev/tags/vim/</link> - <description>Recent content in vim on REPL: Rest-Eat-Program Loop</description> - <generator>Hugo -- gohugo.io</generator> - <language>ja-JP</language> - <lastBuildDate>Sat, 02 Oct 2021 09:37:25 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/vim/feed.xml" rel="self" type="application/rss+xml" /> - <item> - <title>Vimで選択した行の順番を入れ替える</title> - <link>https://blog.nsfisis.dev/posts/2021-10-02/vim-swap-order-of-selected-lines/</link> - <pubDate>Sat, 02 Oct 2021 09:37:25 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2021-10-02/vim-swap-order-of-selected-lines/</guid> - <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。 -元 URL: <a href="https://qiita.com/nsfisis/items/4fefb361d9a693803520">https://qiita.com/nsfisis/items/4fefb361d9a693803520</a></p> -<hr> -<h1 id="バージョン情報">バージョン情報</h1> -<p><code>:version</code> の一部</p> -<blockquote> -<p>VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Jan 26 2020 11:30:30) -macOS version -Included patches: 1-148 -Huge version without GUI.</p> -</blockquote> -<h1 id="よく紹介されている手法">よく紹介されている手法</h1> -<h2 id="tac--tail"><code>tac</code> / <code>tail</code></h2> -<p><code>tac</code> や <code>tail -r</code> などの外部コマンドを <code>!</code> を使って呼び出し、置き換える。</p> -<blockquote> -<p>:h v_!</p> -</blockquote> -<p><code>tac</code> コマンドや <code>tail</code> の <code>-r</code> オプションは環境によって利用できないことがあり、複数の環境を行き来する場合に採用しづらい</p> -<h2 id="gm0"><code>:g/^/m0</code></h2> -<p>こちらは外部コマンドに頼らず、Vim の機能のみを使う。<code>g</code> は <code>:global</code> コマンドの、<code>m</code> は <code>:move</code> コマンドの略</p> -<p><code>:global</code> コマンドは <code>:[range]global/{pattern}/[command]</code> のように使い、<code>[range]</code> で指定された範囲の行のうち、<code>{pattern}</code> で指定された検索パターンにマッチする行に対して、順番に <code>[command]</code> で指定された Ex コマンドを呼び出す。</p> -<blockquote> -<p>:h :global</p> -</blockquote> -<p><code>:move</code> コマンドは <code>[range]:move {address}</code> のように使い、<code>[range]</code> で指定された範囲の行を <code>{address}</code> で指定された位置に移動させる。</p> -<blockquote> -<p>:h :move</p> -</blockquote> -<p><code>:g/^/m0</code> のように組み合わせると、「すべての行を1行ずつ 0行目(1行目の上)に動かす」という動きをする。これは確かに行の入れ替えになっている。</p> -<p>なお、<code>:g/^/m0</code> は全ての行を入れ替えるが、<code>:N,Mg/^/mN-1</code> とすることで N行目から M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#a6e22e">command</span>! -<span style="color:#a6e22e">bar</span> -<span style="color:#a6e22e">range</span>=%<span style="color:#960050;background-color:#1e0010"> -</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">Reverse</span><span style="color:#960050;background-color:#1e0010"> -</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <<span style="color:#a6e22e">line1</span>>,<<span style="color:#a6e22e">line2</span>><span style="color:#a6e22e">g</span><span style="color:#e6db74">/^/</span><span style="color:#a6e22e">m</span><<span style="color:#a6e22e">line1</span>><span style="color:#ae81ff">-1</span><span style="color:#960050;background-color:#1e0010"> -</span></span></span></code></pre></div><p>これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。</p> -<h1 id="gm0-の問題点"><code>:g/^/m0</code> の問題点</h1> -<p><code>:global</code> コマンドは各行に対してマッチングを行う際、現在の検索パターンを上書きしてしまう。<code>^</code> は行の先頭にマッチするため、結果として全ての行がハイライトされてしまう。<code>'hlsearch'</code> オプションを無効にしている場合その限りではないが、その場合でも直前の検索パターンが失われてしまうと <code>n</code> コマンドなどの際に不便である。</p> -<blockquote> -<p>:h @/</p> -</blockquote> -<h1 id="解決策">解決策</h1> -<blockquote> -<p>[2020/9/28追記] -より簡潔な方法を見つけたので次節に追記した</p> -</blockquote> -<p>前述した <code>:Reverse</code> コマンドの定義を少し変えて、次のようにする:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#66d9ef">function</span>! <span style="color:#a6e22e">s</span>:<span style="color:#a6e22e">reverse_lines</span>(<span style="color:#a6e22e">from</span>, <span style="color:#a6e22e">to</span>) <span style="color:#a6e22e">abort</span><span style="color:#960050;background-color:#1e0010"> -</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#a6e22e">execute</span> <span style="color:#a6e22e">printf</span>(<span style="color:#e6db74">"%d,%dg/^/m%d"</span>, <span style="color:#a6e22e">a</span>:<span style="color:#a6e22e">from</span>, <span style="color:#a6e22e">a</span>:<span style="color:#a6e22e">to</span>, <span style="color:#a6e22e">a</span>:<span style="color:#a6e22e">from</span> - <span style="color:#ae81ff">1</span>)<span style="color:#960050;background-color:#1e0010"> -</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">endfunction</span><span style="color:#960050;background-color:#1e0010"> -</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"> -</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">command</span>! -<span style="color:#a6e22e">bar</span> -<span style="color:#a6e22e">range</span>=%<span style="color:#960050;background-color:#1e0010"> -</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">Reverse</span><span style="color:#960050;background-color:#1e0010"> -</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">call</span> <<span style="color:#a6e22e">SID</span>><span style="color:#a6e22e">reverse_lines</span>(<<span style="color:#a6e22e">line1</span>>, <<span style="color:#a6e22e">line2</span>>)<span style="color:#960050;background-color:#1e0010"> -</span></span></span></code></pre></div><p>実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。</p> -<p>この理由は、ユーザー定義関数を実行する際は検索パターンが一度保存され、実行が終了したあと復元されるため。結果として検索パターンが <code>^</code> で上書きされることがなくなる。</p> -<p>Vim のヘルプから該当箇所を引用する (強調は筆者による)。</p> -<blockquote> -<p>:h autocmd-searchpat</p> -<p><strong>Autocommands do not change the current search patterns.</strong> Vim saves the current -search patterns before executing autocommands then restores them after the -autocommands finish. This means that autocommands do not affect the strings -highlighted with the ‘hlsearch’ option.</p> -</blockquote> -<p>これは autocommand の実行に関しての記述だが、これと同じことがユーザー定義関数の実行時にも適用される。このことは <code>:nohlsearch</code> のヘルプにある。同じく該当箇所を引用する (強調は筆者による)。</p> -<blockquote> -<p>:h :nohlsearch</p> -<p>(略) This command doesn’t work in an autocommand, because -the highlighting state is saved and restored when -executing autocommands |autocmd-searchpat|. -<strong>Same thing for when invoking a user function.</strong></p> -</blockquote> -<p>この仕様により、<code>:g/^/m0</code> の呼び出しをユーザー定義関数に切り出すことで上述の問題を解決できる。</p> -<h1 id="解決策-改訂版">解決策 (改訂版)</h1> -<blockquote> -<p>[2020/9/28追記] -より簡潔な方法を見つけたため追記する</p> -</blockquote> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#a6e22e">command</span>! -<span style="color:#a6e22e">bar</span> -<span style="color:#a6e22e">range</span>=%<span style="color:#960050;background-color:#1e0010"> -</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">Reverse</span><span style="color:#960050;background-color:#1e0010"> -</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">keeppatterns</span> <<span style="color:#a6e22e">line1</span>>,<<span style="color:#a6e22e">line2</span>><span style="color:#a6e22e">g</span><span style="color:#e6db74">/^/</span><span style="color:#a6e22e">m</span><<span style="color:#a6e22e">line1</span>><span style="color:#ae81ff">-1</span><span style="color:#960050;background-color:#1e0010"> -</span></span></span></code></pre></div><p>まさにこのための Exコマンド、<code>:keeppatterns</code> が存在する。<code>:keeppatterns {command}</code> のように使い、読んで字の如く、後ろに続く Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。</p> -<blockquote> -<p>:h :keeppatterns</p> -</blockquote> -<h1 id="コピペ用再掲">コピペ用再掲</h1> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#75715e">" License: Public Domain</span><span style="color:#960050;background-color:#1e0010"> -</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"> -</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">command</span>! -<span style="color:#a6e22e">bar</span> -<span style="color:#a6e22e">range</span>=%<span style="color:#960050;background-color:#1e0010"> -</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">Reverse</span><span style="color:#960050;background-color:#1e0010"> -</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">keeppatterns</span> <<span style="color:#a6e22e">line1</span>>,<<span style="color:#a6e22e">line2</span>><span style="color:#a6e22e">g</span><span style="color:#e6db74">/^/</span><span style="color:#a6e22e">m</span><<span style="color:#a6e22e">line1</span>><span style="color:#ae81ff">-1</span><span style="color:#960050;background-color:#1e0010"> -</span></span></span></code></pre></div>]]></description> - </item> - - <item> - <title>[Vim] autocmd events の BufWrite/BufWritePre の違い</title> - <link>https://blog.nsfisis.dev/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/</link> - <pubDate>Sat, 02 Oct 2021 09:37:12 +0900</pubDate> - - <guid>https://blog.nsfisis.dev/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/</guid> - <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。 -元 URL: <a href="https://qiita.com/nsfisis/items/79ab4db8564032de0b25">https://qiita.com/nsfisis/items/79ab4db8564032de0b25</a></p> -<hr> -<h1 id="tl-dr">TL; DR</h1> -<p>違いはない。ただのエイリアス。</p> -<h1 id="調査記録">調査記録</h1> -<p>Vim の autocmd events には似通った名前のものがいくつかある。大抵は <code>:help</code> に説明があるが、この記事のタイトルにある2つを含めた以下のイベントには、その違いについて説明がない。</p> -<ul> -<li><code>BufRead</code>/<code>BufReadPost</code></li> -<li><code>BufWrite</code>/<code>BufWritePre</code></li> -<li><code>BufAdd</code>/<code>BufCreate</code></li> -</ul> -<p>このうち、<code>BufAdd</code>/<code>BufCreate</code> に関しては、<code>:help BufCreate</code> に</p> -<blockquote> -<p>The BufCreate event is for historic reasons.</p> -</blockquote> -<p>とあり、おそらくは <code>BufAdd</code> のエイリアスであろうということがわかる。他の2組も同様ではないかと予想されるが、確認のため vim と neovim のソースコードを調査した。</p> -<blockquote> -<p>ソースコードへのリンク -<a href="https://github.com/vim/vim/tree/8e6be34338f13a6a625f19bcef82019c9adc65f2">vim (調査時点での master branch)</a> -<a href="https://github.com/neovim/neovim/tree/71d4f5851f068eeb432af34850dddda8cc1c71e3">neovim (上に同じ)</a></p> -</blockquote> -<h2 id="vim-のソースコード">vim のソースコード</h2> -<p>以下は、autocmd events の名前と内部で使われている整数値とのマッピングを定義している箇所である。見ての通り、上でエイリアスではないかと述べた3組には、それぞれ同じ内部値が使われている。</p> -<p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86</a></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span> {<span style="color:#e6db74">"BufAdd"</span>, EVENT_BUFADD}, -</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">"BufCreate"</span>, EVENT_BUFADD}, -</span></span></code></pre></div><p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97</a></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span> {<span style="color:#e6db74">"BufRead"</span>, EVENT_BUFREADPOST}, -</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">"BufReadCmd"</span>, EVENT_BUFREADCMD}, -</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">"BufReadPost"</span>, EVENT_BUFREADPOST}, -</span></span></code></pre></div><p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105</a></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span> {<span style="color:#e6db74">"BufWrite"</span>, EVENT_BUFWRITEPRE}, -</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">"BufWritePost"</span>, EVENT_BUFWRITEPOST}, -</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">"BufWritePre"</span>, EVENT_BUFWRITEPRE}, -</span></span></code></pre></div><h2 id="neovim-のソースコード">neovim のソースコード</h2> -<p>neovim の場合でも同様のマッピングが定義されているが、こちらの場合は Lua で書かれている。以下にある通り、はっきり <code>aliases</code> と書かれている。</p> -<p><a href="https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124">https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124</a></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span> aliases <span style="color:#f92672">=</span> { -</span></span><span style="display:flex;"><span> BufCreate <span style="color:#f92672">=</span> <span style="color:#e6db74">'BufAdd'</span>, -</span></span><span style="display:flex;"><span> BufRead <span style="color:#f92672">=</span> <span style="color:#e6db74">'BufReadPost'</span>, -</span></span><span style="display:flex;"><span> BufWrite <span style="color:#f92672">=</span> <span style="color:#e6db74">'BufWritePre'</span>, -</span></span><span style="display:flex;"><span> FileEncoding <span style="color:#f92672">=</span> <span style="color:#e6db74">'EncodingChanged'</span>, -</span></span><span style="display:flex;"><span> }, -</span></span></code></pre></div><p>ところで、上では取り上げなかった <code>FileEncoding</code> だが、これは <code>:help FileEncoding</code> にしっかりと書いてある。</p> -<pre tabindex="0"><code> *FileEncoding* -FileEncoding Obsolete. It still works and is equivalent - to |EncodingChanged|. -</code></pre><h2 id="まとめ">まとめ</h2> -<p>記事タイトルについて言えば、どちらも変わらないので好きな方を使えばよい。あえて言えば、次のようになるだろう。</p> -<ul> -<li><code>BufAdd</code>/<code>BufCreate</code> -<ul> -<li>→ <code>BufCreate</code> は歴史的な理由により (“for historic reasons”) 存在しているため、新しい方 (<code>BufAdd</code>) を使う</li> -</ul> -</li> -<li><code>BufRead</code>/<code>BufReadPost</code> -<ul> -<li>→ <code>BufReadPre</code> との対称性のため、あるいは <code>BufWritePost</code> との対称性のため <code>BufReadPost</code> を使う</li> -</ul> -</li> -<li><code>BufWrite</code>/<code>BufWritePre</code> -<ul> -<li>→ <code>BufWritePost</code> との対称性のため、あるいは <code>BufReadPre</code> との対称性のため <code>BufWritePre</code> を使う</li> -</ul> -</li> -<li><code>FileEncoding</code>/<code>EncodingChanged</code> -<ul> -<li>→ <code>FileEncoding</code> は “Obsolete” と明言されているので、<code>EncodingChanged</code> を使う</li> -</ul> -</li> -</ul> -<p>ところでこの調査で知ったのだが、<code>BufRead</code> と <code>BufWrite</code> は上にある通り発火するタイミングが「後」と「前」で対称性がない。可能なら <code>Pre</code>/<code>Post</code> 付きのものを使った方が分かりやすいだろう。</p> -]]></description> - </item> - - </channel> -</rss> diff --git a/docs/tags/vim/index.html b/docs/tags/vim/index.html deleted file mode 100644 index 5964ab8..0000000 --- a/docs/tags/vim/index.html +++ /dev/null @@ -1,68 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - - <title>vim | REPL: Rest-Eat-Program Loop</title> - - <meta name="description" content=""> - <meta name="author" content="nsfisis"> - - <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet"> - - <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg"> - <meta name="generator" content="Hugo 0.102.1" /> - - <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/vim/feed.xml" title="REPL: Rest-Eat-Program Loop" /> - - </head> - <body class="list"> - <header class="header"> - <nav class="nav"> - <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p> - </nav> - </header> - <main class="main"> - -<header class="page-header"><h1>vim</h1></header> - -<article class="post-entry"> - <header class="entry-header"> - <h2>Vimで選択した行の順番を入れ替える</h2> - </header> - <section class="entry-content"> - <p>Vim で選択した行の順番を入れ替える方法。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2021-10-02</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/vim-swap-order-of-selected-lines/"></a> -</article> -<article class="post-entry"> - <header class="entry-header"> - <h2>[Vim] autocmd events の BufWrite/BufWritePre の違い</h2> - </header> - <section class="entry-content"> - <p>Vim の autocmd events における BufWrite/BufWritePre がどう違うのかを調べた結果、違いはないことがわかった。</p> - </section> - <footer class="entry-footer"> - Posted on <time>2021-10-02</time> - </footer> - <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/"></a> -</article></main> -<footer class="footer"> - <span>© 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span> - <span>·</span> - <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span> -</footer> -<script src="https://blog.nsfisis.dev/highlight.min.js"></script> -<script> - hljs.initHighlightingOnLoad(); -</script> -</body> -</html> - diff --git a/docs/tags/vim/page/1/index.html b/docs/tags/vim/page/1/index.html deleted file mode 100644 index 52be41d..0000000 --- a/docs/tags/vim/page/1/index.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <title>https://blog.nsfisis.dev/tags/vim/</title> - <link rel="canonical" href="https://blog.nsfisis.dev/tags/vim/"> - <meta name="robots" content="noindex"> - <meta charset="utf-8"> - <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/vim/"> - </head> -</html> |
