diff options
Diffstat (limited to 'public/posts')
4 files changed, 355 insertions, 341 deletions
diff --git a/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html b/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html index 3197780..dd6da27 100644 --- a/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html +++ b/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html @@ -110,10 +110,10 @@ end</code></pre> </p> <pre class="monospaced highlight"><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> +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>か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。 diff --git a/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html b/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html index 4d63296..480c2eb 100644 --- a/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html +++ b/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html @@ -126,79 +126,79 @@ </p> <pre class="highlight" language="c" linenumbering="unnumbered"><code>#\ - i\ - n\ - c\ - l\ - u\ - d\ - e\ - <\ - s\ - t\ - d\ - i\ - o\ - .\ - h\ - >\ - /* - */ - i\ - n\ - t\ - /* - */ - m\ - a\ - i\ - n( - ){ - f\ - o\ - r( - i\ - n\ - t\ - /* - */ - i= - 1; - i< - 1\ - 0\ - 0; - i\ - +\ - +) - if - (i - %\ - 15 - == - 0) - p\ - r\ - i\ - n\ - t\ - f( - "\ - F\ - i\ - z\ - z\ - B\ - u\ - z\ - z\ - %\ - c\ - ", - 10 - ); +i\ +n\ +c\ +l\ +u\ +d\ +e\ +<\ +s\ +t\ +d\ +i\ +o\ +.\ +h\ +>\ +/* +*/ +i\ +n\ +t\ +/* +*/ +m\ +a\ +i\ +n( +){ +f\ +o\ +r( +i\ +n\ +t\ +/* +*/ +i= +1; +i< +1\ +0\ +0; +i\ ++\ ++) +if +(i +%\ +15 +== +0) +p\ +r\ +i\ +n\ +t\ +f( +"\ +F\ +i\ +z\ +z\ +B\ +u\ +z\ +z\ +%\ +c\ +", +10 +); - /* あとは同じように普通のプログラムを変形するだけなので省略 */</code></pre> +/* あとは同じように普通のプログラムを変形するだけなので省略 */</code></pre> <p> バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。 @@ -280,11 +280,11 @@ a' まずは普通に書くとしよう。 </p> - <pre class="monospaced highlight"><code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php - for ($i = 1; $i < 100; $i++) { - echo (($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"; - }</code></pre> +for ($i = 1; $i < 100; $i++) { + echo (($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"; +}</code></pre> <p> 素直に書いた fizzbuzz とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。 @@ -299,12 +299,12 @@ a' <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php - $s = range(1, 100); - array_walk( +$s = range(1, 100); +array_walk( $s, fn($i) => - printf((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"), - );</code></pre> + printf((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"), +);</code></pre> <p> <code>array_walk</code>や<code>range</code>、<code>printf</code>といった<code>for</code>よりも長いトークンが現れてしまったが、これは次節で直すことにする。なお、<code>echo</code>は文 (statement) であり式 (expression) ではないので、式である<code>printf</code>に置き換えた。 @@ -319,16 +319,16 @@ a' <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php - $r = 'range'; - $w = 'array_walk'; - $p = 'printf'; +$r = 'range'; +$w = 'array_walk'; +$p = 'printf'; - $s = $r(1, 100); - $w( +$s = $r(1, 100); +$w( $s, fn($i) => - $p((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"), - );</code></pre> + $p((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"), +);</code></pre> <p> これで関数を呼び出している所は短くなった。では、<code>$r</code>や<code>$w</code>や<code>$p</code>、また<code>'Fizz'</code>や<code>'Buzz'</code>はどうやって 1行2文字に収めるのか。次のテクニックへ移ろう。 @@ -470,153 +470,153 @@ echo "$r\n";</code></pre> <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php - $x - =# - 'i - S' - ;; - $y - =' - b! - '; - $c - =# - $x - ^# - $y - ;# - $x - =# - 'x - Om - '; - $y - =' - k! - o' - ;# - $r - =# - $x - ^# - $y - ;# - $x - =# - 'k - Sk - ~} - Ma - '; - $y - =' - x! - s! - k! - '; - $w - =# - $x - ^# - $y - ;# - $x - =# - 'z - Hd - G' - ;# - $y - =' - x! - ~! - '; - $p - =# - $x - ^# - $y - ;# - $x - =# - 'L - [p - '; - $y - =' - c! - '; - $f - =# - $x - ^# - $y - ;# - $x - =# - 'H - [p - '; - $y - =' - _! - '; - $b - =# - $x - ^# - $y - ;# - $b - [1 - ]= - $c - (# - 13 - *9 - ); - $s - =# - $r - (1 - ,( - 10 - ** - 2) - ); - $w - (# - $s - ,# - fn - (# - $i - )# - => - $p - (( - (# - $i - %3 - ?# - '' - :# - $f - ). - (# - $i - %5 - ?# - '' - :# - $b - )? - :# - $i - )# - .' - ') - );</code></pre> +$x +=# +'i +S' +;; +$y +=' +b! +'; +$c +=# +$x +^# +$y +;# +$x +=# +'x +Om +'; +$y +=' +k! +o' +;# +$r +=# +$x +^# +$y +;# +$x +=# +'k +Sk +~} +Ma +'; +$y +=' +x! +s! +k! +'; +$w +=# +$x +^# +$y +;# +$x +=# +'z +Hd +G' +;# +$y +=' +x! +~! +'; +$p +=# +$x +^# +$y +;# +$x +=# +'L +[p +'; +$y +=' +c! +'; +$f +=# +$x +^# +$y +;# +$x +=# +'H +[p +'; +$y +=' +_! +'; +$b +=# +$x +^# +$y +;# +$b +[1 +]= +$c +(# +13 +*9 +); +$s +=# +$r +(1 +,( +10 +** +2) +); +$w +(# +$s +,# +fn +(# +$i +)# +=> +$p +(( +(# +$i +%3 +?# +'' +:# +$f +). +(# +$i +%5 +?# +'' +:# +$b +)? +:# +$i +)# +.' +') +);</code></pre> </section> <section id="section--_感想など"> @@ -638,16 +638,16 @@ echo "$r\n";</code></pre> <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php - printf(` - e\ - c\ - h\ - o\ - \ - 1\ - 2\ - 3\ - `);</code></pre> +printf(` +e\ +c\ +h\ +o\ +\ +1\ +2\ +3\ +`);</code></pre> <p> なお、ここでは簡単のため出力に<code>printf</code>をそのまま使っているが、実際には<code>printf</code>という文字列を合成して可変関数で呼び出す。 diff --git a/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html b/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html index dcc0de8..be78585 100644 --- a/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html +++ b/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html @@ -72,7 +72,8 @@ 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <pre class="highlight" language="php" linenumbering="unnumbered"><code> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> @@ -81,7 +82,8 @@ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?></code></pre> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + </code></pre> <p> "And Then There Were None" (そして誰もいなくなった) と名付けた作品。変則 quine (自分自身と同じソースコードを出力するプログラム) になっている。 @@ -94,7 +96,8 @@ 実行してみると、次のような出力が得られる。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code># + <pre class="highlight" language="php" linenumbering="unnumbered"><code> + # <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> @@ -103,13 +106,15 @@ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?></code></pre> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + </code></pre> <p> 1 行目を除き、先ほどのコードとほぼ同じものが出てきた。もう一度実行してみる。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code># + <pre class="highlight" language="php" linenumbering="unnumbered"><code> + # W <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> @@ -118,22 +123,25 @@ W <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> -<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?></code></pre> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> +</code></pre> <p> 今度は 2 行目が書き換えられた。すべての行が変化するまで繰り返すと次のようになる。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code># -W -E -L -O -V -E -P -H -P</code></pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code> + # + W + E + L + O + V + E + P + H + P +</code></pre> <p> トークン「#WELOVEPHP」が手に入った。 @@ -150,7 +158,9 @@ P</code></pre> Vim で開くと次のようになる (1 行目を抜粋)。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?></code></pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code> + <?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + </code></pre> <p> <code><200b></code>と表示されているのは、Unicode の U+200b で、ゼロ幅スペースである。 @@ -175,13 +185,17 @@ P</code></pre> 続いて、トークンへの変換ロジックを解析する。注目すべきはこの部分だ。以下、ゼロ幅スペースは Vim での表示に合わせて<code><200b></code>と記載する。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code>fn($s)=>chr(strlen($s)/3)</code></pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code> + fn($s)=>chr(strlen($s)/3) + </code></pre> <p> PHP の<code>strlen()</code>は文字列のバイト数を返す。1 行目の<code>$s</code>は以下の内容となっており、 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code>$s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</code></pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code> + $s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>' + </code></pre> <p> このソースコードは UTF-8 で書かれているので、105 バイトになる。それを 3 で割ると 35 となり、これは<code>#</code>の ASCII コードと一致する。他の行も、同様にしてゼロ幅スペースを詰めることで文字列長を調整し、トークンをエンコードしている。 diff --git a/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html b/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html index 6896530..a7f86b3 100644 --- a/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html +++ b/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html @@ -83,23 +83,23 @@ </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php - try { - f(g() / __LINE__); - } catch (Throwable $e) { - while ($e = $e->getPrevious()) printf('%c', $e->getLine() + 23); - echo "\n"; - } - function f(int $i) { - if ($i < 0) f(); - try { +try { + f(g() / __LINE__); +} catch (Throwable $e) { + while ($e = $e->getPrevious()) printf('%c', $e->getLine() + 23); + echo "\n"; +} +function f(int $i) { + if ($i < 0) f(); + try { match ($i) { - 0 => 0 / 0, + 0 => 0 / 0, - 15, 36 => 0 / 0, - 14 => 0 / 0, - 37 => 0 / 0, + 15, 36 => 0 / 0, + 14 => 0 / 0, + 37 => 0 / 0, @@ -110,16 +110,16 @@ - 6 => 0 / 0, + 6 => 0 / 0, - 5 => 0 / 0, + 5 => 0 / 0, - 22 => 0 / 0, + 22 => 0 / 0, - 34, 35 => 0 / 0, + 34, 35 => 0 / 0, @@ -128,10 +128,10 @@ - 25 => 0 / 0, - 17, 21 => 0 / 0, + 25 => 0 / 0, + 17, 21 => 0 / 0, - 24, 32 => 0 / 0, + 24, 32 => 0 / 0, @@ -139,12 +139,12 @@ - 33 => 0 / 0, + 33 => 0 / 0, - 16 => 0 / 0, + 16 => 0 / 0, - 18 => 0 / 0, + 18 => 0 / 0, @@ -153,37 +153,37 @@ - 7 => 0 / 0, + 7 => 0 / 0, - 2 => 0 / 0, - 1, 20 => 0 / 0, - 10, 28 => 0 / 0, - 8, 12, 26 => 0 / 0, - 4, 9, 13 => 0 / 0, + 2 => 0 / 0, + 1, 20 => 0 / 0, + 10, 28 => 0 / 0, + 8, 12, 26 => 0 / 0, + 4, 9, 13 => 0 / 0, - 31 => 0 / 0, + 31 => 0 / 0, - 29 => 0 / 0, + 29 => 0 / 0, - 11 => 0 / 0, + 11 => 0 / 0, - 3, 19, 23 => 0 / 0, + 3, 19, 23 => 0 / 0, - 27 => 0 / 0, + 27 => 0 / 0, - 30 => 0 / 0, + 30 => 0 / 0, }; - } finally { + } finally { f($i - 1); - } - } + } +} @@ -191,9 +191,9 @@ - function g() { - return __LINE__; - }</code></pre> +function g() { + return __LINE__; +}</code></pre> <p> "Catchline" と名付けた作品。実行するとトークン<code>#base64_decode('SGVsbG8sIFdvcmxkIQ==')</code>が得られる。 @@ -239,18 +239,18 @@ <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php - try { - try { - throw new Exception("Error 1"); - } finally { - throw new Exception("Error 2"); - } - } catch (Exception $e) { - echo $e->getMessage() . PHP_EOL; - // => Error 2 - echo $e->getPrevious()->getMessage() . PHP_EOL; - // => Error 1 - }</code></pre> +try { + try { + throw new Exception("Error 1"); + } finally { + throw new Exception("Error 2"); + } +} catch (Exception $e) { + echo $e->getMessage() . PHP_EOL; + // => Error 2 + echo $e->getPrevious()->getMessage() . PHP_EOL; + // => Error 1 +}</code></pre> <p> この知識を元に、トークンの出力部を解析してみる。 @@ -264,14 +264,14 @@ </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php - try { - f(g() / __LINE__); - } catch (Throwable $e) { - while ($e = $e->getPrevious()) { - printf('%c', $e->getLine() + 23); - } - echo "\n"; - }</code></pre> +try { + f(g() / __LINE__); +} catch (Throwable $e) { + while ($e = $e->getPrevious()) { + printf('%c', $e->getLine() + 23); + } + echo "\n"; +}</code></pre> <p> 出力をおこなう<code>catch</code>節を見てみると、<code>Throwable::getPrevious()</code>を呼び出してエラーチェインを辿り、<code>Throwable::getLine()</code>でエラーが発生した行数を取得している。その行数に<code>23</code>なるマジックナンバーを足し、フォーマット指定子<code>%c</code>で出力している。 @@ -281,7 +281,7 @@ フォーマット指定子<code>%c</code>は、整数を ASCII コード<span></span>と見做して印字する。トークン<code>#base64_decode('SGVsbG8sIFdvcmxkIQ==')</code>の<code>b</code>であれば、ASCII コード<code>98</code>なので、75 行目で発生したエラー、 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code> 1, 20 => 0 / 0,</code></pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code>1, 20 => 0 / 0,</code></pre> <p> によって表現されている。エラーを起こす方法はいろいろと考えられるが、今回はゼロ除算を使った。 @@ -299,9 +299,9 @@ </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code>function f(int $i) { - if ($i < 0) f(); - try { - match ($i) { + if ($i < 0) f(); + try { + match ($i) { 0 => 0 / 0, // 12 行目 @@ -313,23 +313,23 @@ // (略) 30 => 0 / 0, // 97 行目 - }; - } finally { - f($i - 1); - } - }</code></pre> + }; + } finally { + f($i - 1); + } +}</code></pre> <p> 前述のように、<code>finally</code>節でエラーを投げると PHP 処理系が<code>$previous</code>を設定する。ここでは、エラーを繋げるために<code>f()</code>を再帰呼び出ししている。最初に<code>f()</code>を呼び出している箇所を確認すると、 </p> <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php - try { - f(g() / __LINE__); // 3 行目</code></pre> +try { + f(g() / __LINE__); // 3 行目</code></pre> <pre class="highlight" language="php" linenumbering="unnumbered"><code>function g() { - return __LINE__; // 111 行目 - }</code></pre> + return __LINE__; // 111 行目 +}</code></pre> <p> <code>f()</code>には<code>111 / 3</code>で<code>37</code>が渡されることがわかる。そこから 1 ずつ減らして再帰呼び出ししていき、0 より小さくなったら<code>f()</code>を引数なしで呼び出す。引数の数が足りないと呼び出しに失敗するので、再帰はここで止まる。 |
