{
    "componentChunkName": "component---src-templates-blog-post-jsx",
    "path": "/post/how-to-implement-find-all-by-with-php-magic-method/",
    "result": {"data":{"site":{"siteMetadata":{"title":"WEB EGG","author":"Leko - CTO at Yuimedi"}},"markdownRemark":{"id":"28c34a60-50a9-555d-9ee8-338fe14ee2b1","excerpt":"久々の更新です。 ネタは溜まっているんですがなかなか書くモチベが沸かず。 これから定期的に更新できるよう頑張ります。 今日はPHPのマジックメソッドについて書きます。 PHPのマジックメソッドの中に__callStaticというメソッドがあります。 これは、クラスで定義されていないメソッドに対してstatic…","html":"<p>久々の更新です。<br>\nネタは溜まっているんですがなかなか書くモチベが沸かず。</p>\n<p>これから定期的に更新できるよう頑張ります。</p>\n<p>今日はPHPのマジックメソッドについて書きます。</p>\n<p>PHPのマジックメソッドの中に<code>__callStatic</code>というメソッドがあります。<br>\nこれは、クラスで定義されていないメソッドに対してstaticなコールをした際に呼び出されるフックです。</p>\n<p>この機能を使えば、Rubyでいうところの<code>method missing</code>のような挙動が可能になるのでは？<br>\nと考え、実験にRuby on Railsで以前まで使われていた<code>find_all_by_*</code>を実装してみたいと思います。</p>\n<p>ライブラリ等に依存しないシンプルなデモと、<br>\n実用化するために、<code>FuelPHP</code>のモデルを用いた例も作成します。</p>\n<!--more-->\n<h2 id=\"__callstaticの仕様を読む\" style=\"position:relative;\"><a href=\"#__callstatic%E3%81%AE%E4%BB%95%E6%A7%98%E3%82%92%E8%AA%AD%E3%82%80\" aria-label=\"__callstaticの仕様を読む permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>__callStaticの仕様を読む</h2>\n<blockquote>\n<p>__callStatic() は、 アクセス不能メソッドを静的コンテキストで実行したときに起動します。</p>\n<p>引数 $name は、 コールしようとしたメソッドの名前です。 引数 $arguments は配列で、メソッド $name に渡そうとしたパラメータが格納されます。<br>\n— <a href=\"http://php.net/manual/ja/language.oop5.overloading.php#object.callstatic\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">PHP: オーバーロード – Manual</a></p>\n</blockquote>\n<p>サンプルコードを呼んでみると、<code>__callStatic</code>はPHP 5.3以上で動作可能な機能のようです。</p>\n<p>引数の説明が分かりにくいので、コードを交えつつ解説します。</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\"><span class=\"token php language-php\"><span class=\"token delimiter important\">&lt;?php</span>\n\n<span class=\"token keyword\">class</span> <span class=\"token class-name-definition class-name\">Sample</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">public</span> <span class=\"token keyword\">static</span> <span class=\"token keyword\">function</span> <span class=\"token function-definition function\">__callStatic</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$name</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$args</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token function\">var_dump</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$name</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$args</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token class-name static-context\">Sample</span><span class=\"token operator\">::</span><span class=\"token function\">hogehoge</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">,</span><span class=\"token number\">2</span><span class=\"token punctuation\">,</span><span class=\"token number\">3</span><span class=\"token punctuation\">,</span><span class=\"token number\">4</span><span class=\"token punctuation\">,</span><span class=\"token number\">5</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></span></code></pre></div>\n<p>\n  こんなコードがあったとします。<br />\n  <code>Sample::hogehoge()</code>をコールすると、Sampleクラスにはhogehogeメソッドが定義されていないため、<code>__callStatic</code>が呼び出されます。<br />\n  このとき、$nameにはメソッド名である<code>hogehoge</code>が、$argsにはhogehogeに渡した引数である<code>[1, 2, 3, 4, 5]</code>が配列で格納されています。\n</p>\n<p>\n  これを利用して、<code>find_all_by_*</code>を実装してみたいと思います。\n</p>\n<h2>\n  find_all_by_* とは？\n</h2>\n<p>\n  先ほどから出ているfind_all_byメソッドとは何でしょうか。<br />\n  やや古いRails(3.2.*)まで使用されていたデータ検索用のメソッドです。\n</p>\n<blockquote>\n  <p>\n    カラム名を指定して、検索条件にあうすべてのレコードを取得する。<br />\n      rails4からは、whereで代替することができる。<br />\n      &mdash; <a href=\"http://railsdoc.com/references/find_all_by\">find_all_by - リファレンス - Railsドキュメント</a>\n  </p>  \n</blockquote>\n<p>\n  4.*系からは非推奨になってしまいました。<br />\n  とはいえ、今回はあくまで__callStaticが活躍できそうな方法を探ることが目的なので構わず実装します。\n</p>\n<h2 id=\"仕様\" style=\"position:relative;\"><a href=\"#%E4%BB%95%E6%A7%98\" aria-label=\"仕様 permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>仕様</h2>\n<p>\n  単一のカラムの指定も受け付け、<br />\n  更に<code>_and_</code>で繋いだ複数カラムと値の組み合わせを受け付ける<br />\n  というものを作ってみたいと思います。\n</p>\n<p>\n  例えば、<code>クラス名::カラム名1_and_カラム名2(値1, 値2)</code>とメソッドを呼び出せば、__callStatic内では<br />\n  <code>SELECT * FROM クラス名 WHERE カラム名1=値1 AND カラム名2=値2</code><br />\n  と解釈してもらうことにします。\n</p>\n<p>\n  なお、このメソッドでは、カラム名に<code>and</code>が含まれることを考慮しません。\n</p>\n<h2 id=\"クラスを定義\" style=\"position:relative;\"><a href=\"#%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%92%E5%AE%9A%E7%BE%A9\" aria-label=\"クラスを定義 permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>クラスを定義</h2>\n<p>\n  まずは、２つのクラスを作成します。\n</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\"><span class=\"token php language-php\"><span class=\"token delimiter important\">&lt;?php</span>\n\n<span class=\"token keyword\">abstract</span> <span class=\"token keyword\">class</span> <span class=\"token class-name-definition class-name\">Model</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">protected</span> <span class=\"token keyword\">static</span> <span class=\"token variable\">$table_name</span> <span class=\"token operator\">=</span> <span class=\"token constant\">null</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">class</span> <span class=\"token class-name-definition class-name\">Test</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\">Model</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">protected</span> <span class=\"token keyword\">static</span> <span class=\"token variable\">$table_name</span> <span class=\"token operator\">=</span> <span class=\"token string single-quoted-string\">'test'</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></span></code></pre></div>\n<p>\n  <code>Model</code>クラスは抽象クラスで、継承される前提のクラスです。<br />\n  <code>Test</code>クラスはModelクラスを継承し、実際にアプリケーション内で使用されるモデルクラスとします。\n</p>\n<p>\n  テーブル名は、クラス名から取得などをせずに、<br />\n  おとなしく<code>$table_name</code>というプロパティを定義しています。\n</p>\n<h3>\n  検索用メソッドを作成\n</h3>\n<p>\n  マジックメソッドの前に、汎用的な検索メソッドを作成します。<br />\n  連想配列を受け取り、それをSQL文字列に変換するメソッドです。\n</p>\n<p>\n  <code>Test</code>クラスにはこれ以上書くことがないので、以下のコードでは<code>Model</code>クラスのみ記述します。\n</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\"><span class=\"token keyword\">class</span> <span class=\"token class-name-definition class-name\">Model</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> <span class=\"token constant\">FIND_ALL_BY</span> <span class=\"token operator\">=</span> <span class=\"token string single-quoted-string\">'find_all_by_'</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">protected</span> <span class=\"token keyword\">static</span> <span class=\"token variable\">$table_name</span> <span class=\"token operator\">=</span> <span class=\"token string single-quoted-string\">''</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token comment\">// 連想配列を与えて、条件にマッチする行を全件取得するSQLを作成する</span>\n    <span class=\"token keyword\">public</span> <span class=\"token keyword\">static</span> <span class=\"token keyword\">function</span> <span class=\"token function-definition function\">find_all</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$where</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">array</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token variable\">$sql</span> <span class=\"token operator\">=</span> <span class=\"token string single-quoted-string\">'SELECT * FROM '</span><span class=\"token operator\">.</span><span class=\"token keyword static-context\">static</span><span class=\"token operator\">::</span><span class=\"token variable\">$table_name</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token comment\">// 連想配列が指定されていたらWHERE句を生成</span>\n        <span class=\"token keyword\">if</span><span class=\"token punctuation\">(</span><span class=\"token function\">count</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$where</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">></span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token variable\">$keyval</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">array</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token keyword\">foreach</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$where</span> <span class=\"token keyword\">as</span> <span class=\"token variable\">$column</span> <span class=\"token operator\">=></span> <span class=\"token variable\">$value</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                <span class=\"token variable\">$keyval</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token variable\">$column</span><span class=\"token operator\">.</span><span class=\"token string single-quoted-string\">'='</span><span class=\"token operator\">.</span><span class=\"token variable\">$value</span><span class=\"token punctuation\">;</span>\n            <span class=\"token punctuation\">}</span>\n            <span class=\"token variable\">$sql</span> <span class=\"token operator\">.=</span> <span class=\"token string single-quoted-string\">' WHERE '</span><span class=\"token operator\">.</span><span class=\"token function\">implode</span><span class=\"token punctuation\">(</span><span class=\"token string single-quoted-string\">' AND '</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$keyval</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n\n        <span class=\"token keyword\">return</span> <span class=\"token variable\">$sql</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span></code></pre></div>\n<p>\n  <code>find_all</code>というメソッドを追加しました。\n</p>\n<p>\n  \"コピペで使えるコード\"を目指しているわけではないので、SQLの生成自体はかなり適当です。<br />\n  クオートしていないので、クオートが必要な値が含まれていたら実行すらできません。<br />\n  しかし、イメージは十分に伝わると思います。\n</p>\n<p>\n  SQLの作成が雑なのは、自力でSQLを生成するのは非現実的であることと、<br />\n  この後FuelPHP対応の実用版を書くため、<strong>カラム名と値の組み合わせ</strong>という情報さえ手に入れば十分だからです。\n</p>\n<p>\n  ちなみに、<code>findAll</code>メソッドの使用イメージはこんな感じです。\n</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\"><span class=\"token comment\">// \"SELECT * FROM test WHERE id=1\"</span>\n<span class=\"token class-name static-context\">Test</span><span class=\"token operator\">::</span><span class=\"token function\">find_all</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">array</span><span class=\"token punctuation\">(</span><span class=\"token string single-quoted-string\">'id'</span> <span class=\"token operator\">=></span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// \"SELECT * FROM test WHERE name=Leko AND age => 22\"</span>\n<span class=\"token class-name static-context\">Test</span><span class=\"token operator\">::</span><span class=\"token function\">find_all</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">array</span><span class=\"token punctuation\">(</span><span class=\"token string single-quoted-string\">'name'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'Leko'</span><span class=\"token punctuation\">,</span> <span class=\"token string single-quoted-string\">'age'</span> <span class=\"token operator\">=></span> <span class=\"token number\">22</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<h3>\n  マジックメソッドを定義\n</h3>\n<p>\n  本題です。マジックメソッドを入れていきます。<br />\n  先ほど<code>find_all</code>メソッドを作成したので、検索自体は<code>find_all</code>の責務です。<br />\n  そのため<code>__callStatic</code>では、カラム名と値の組み合わせさえ取得できればOKです。<br />\n  <code>find_all</code>へパスする処理を実装します。\n</p>\n<p>\n  全体を書くとやや長くなるため、マジックメソッドのみ記述します。\n</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\"><span class=\"token keyword\">public</span> <span class=\"token keyword\">static</span> <span class=\"token keyword\">function</span> <span class=\"token function-definition function\">__callStatic</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$method_name</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$args</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// メソッド名がfind_all_by_で始まる場合のみ解析を行う</span>\n    <span class=\"token keyword\">if</span><span class=\"token punctuation\">(</span><span class=\"token function\">strpos</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$method_name</span><span class=\"token punctuation\">,</span> <span class=\"token keyword static-context\">self</span><span class=\"token operator\">::</span><span class=\"token constant\">FIND_ALL_BY</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">===</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// find_all_by_を除去</span>\n        <span class=\"token variable\">$method_name</span> <span class=\"token operator\">=</span> <span class=\"token function\">str_replace</span><span class=\"token punctuation\">(</span><span class=\"token keyword static-context\">self</span><span class=\"token operator\">::</span><span class=\"token constant\">FIND_ALL_BY</span><span class=\"token punctuation\">,</span> <span class=\"token string single-quoted-string\">''</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$method_name</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token comment\">// カラム名 => 値の連想配列へ変換</span>\n        <span class=\"token variable\">$columns</span> <span class=\"token operator\">=</span> <span class=\"token function\">explode</span><span class=\"token punctuation\">(</span><span class=\"token string single-quoted-string\">'_and_'</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$method_name</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token variable\">$where</span>   <span class=\"token operator\">=</span> <span class=\"token function\">array_combine</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$columns</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$args</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token keyword\">return</span> <span class=\"token keyword static-context\">self</span><span class=\"token operator\">::</span><span class=\"token function\">find_all</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$where</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<ol>\n  <li>\n    呼び出されたメソッド名が<code>find_all_by_*</code>(※<code>self::FIND_ALL_BY</code>)の書式なら、  \n  </li>  \n  <li>\n    メソッド名を<code>_and_</code>で千切って配列化し、  \n  </li>  \n  <li>\n    <a href=\"http://php.net/manual/ja/function.array-combine.php\">array_combine()</a>関数を使用して<code>カラム名 => 値</code>の連想配列へ変換し、  \n  </li>  \n  <li>\n    それをfind_allメソッドへパスする\n  </li>  \n</ol>\n<p>\n  という処理になっています。\n</p>\n<p>\n  他のマジックメソッドの邪魔をしないために、<br />\n  呼び出されたメソッドの名前が、<code>find_all_by_</code>で始まる場合のみ、処理するようにしています。\n</p>\n<p>\n  使用イメージは以下の通りです。\n</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\"><span class=\"token comment\">// \"SELECT * FROM test WHERE id=1\"</span>\n<span class=\"token class-name static-context\">Test</span><span class=\"token operator\">::</span><span class=\"token function\">find_all_by_id</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// \"SELECT * FROM test WHERE name=Leko\"</span>\n<span class=\"token class-name static-context\">Test</span><span class=\"token operator\">::</span><span class=\"token function\">find_all_by_name</span><span class=\"token punctuation\">(</span><span class=\"token string single-quoted-string\">'Leko'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// \"SELECT * FROM test WHERE name=Leko AND age=22\"</span>\n<span class=\"token class-name static-context\">Test</span><span class=\"token operator\">::</span><span class=\"token function\">find_all_by_name_and_age</span><span class=\"token punctuation\">(</span><span class=\"token string single-quoted-string\">'Leko'</span><span class=\"token punctuation\">,</span> <span class=\"token number\">22</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// \"SELECT * FROM test WHERE name=Leko and created_at=2014-07-20 04:00:00\"</span>\n<span class=\"token class-name static-context\">Test</span><span class=\"token operator\">::</span><span class=\"token function\">find_all_by_name_and_created_at</span><span class=\"token punctuation\">(</span><span class=\"token string single-quoted-string\">'Leko'</span><span class=\"token punctuation\">,</span> <span class=\"token function\">date</span><span class=\"token punctuation\">(</span><span class=\"token string single-quoted-string\">'Y-m-d h:i:s'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>\n  <code>created_at</code>のように、カラム名にアンダースコアが混じっていても問題ありません。\n</p>\n<h3>\n  FuelPHPに組み込んでみる\n</h3>\n<p>\n  本題２です。上記のマジックメソッドを実用化してみます。\n</p>\n<p>\n  FuelPHPを選んだ理由は、<br />\n  メソッド名にアンダースコアを使うことを<a href=\"http://fuelphp.jp/docs/1.7/general/coding_standards.html#methods_standards\">コーディング規約</a>にしているのと、<br />\n  普段業務で使用しているため勝手がわかるという理由からです。\n</p>\n<p>\n  また、自作した<code>find_all</code>メソッドは、<br />\n  同等以上の機能がFuelPHPの<code>find_by</code>メソッドで実現されているためそちらを利用します。\n</p>\n<p>\n  <strong>また、<code>find_by_*</code>というメソッドもサポートしています。</strong>\n</p>\n<p>\n  ・・・気にせず実装します。<br />\n  <code>_and_</code>があれば差別化できますし、車輪の再発明だとしても、勉強のためです。\n</p>\n<p>\n  マジックメソッドをFuelPHPのモデルに組み込むと、下記のようになります。\n</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\"><span class=\"token keyword\">abstract</span> <span class=\"token keyword\">class</span> <span class=\"token class-name-definition class-name\">Model_Base</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\">Model_Crud</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> <span class=\"token constant\">FIND_ALL_BY</span> <span class=\"token operator\">=</span> <span class=\"token string single-quoted-string\">'find_all_by_'</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">protected</span> <span class=\"token keyword\">static</span> <span class=\"token variable\">$_table_name</span> <span class=\"token operator\">=</span> <span class=\"token string single-quoted-string\">'hoges'</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">public</span> <span class=\"token keyword\">static</span> <span class=\"token keyword\">function</span> <span class=\"token function-definition function\">__callStatic</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$method_name</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$args</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// メソッド名がfind_all_by_で始まる場合のみ解析を行う</span>\n        <span class=\"token keyword\">if</span><span class=\"token punctuation\">(</span><span class=\"token function\">strpos</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$method_name</span><span class=\"token punctuation\">,</span> <span class=\"token keyword static-context\">self</span><span class=\"token operator\">::</span><span class=\"token constant\">FIND_ALL_BY</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">===</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token comment\">// find_all_by_を除去</span>\n            <span class=\"token variable\">$method_name</span> <span class=\"token operator\">=</span> <span class=\"token function\">str_replace</span><span class=\"token punctuation\">(</span><span class=\"token keyword static-context\">self</span><span class=\"token operator\">::</span><span class=\"token constant\">FIND_ALL_BY</span><span class=\"token punctuation\">,</span> <span class=\"token string single-quoted-string\">''</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$method_name</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n            <span class=\"token comment\">// カラム名 => 値の連想配列へ変換</span>\n            <span class=\"token variable\">$columns</span> <span class=\"token operator\">=</span> <span class=\"token function\">explode</span><span class=\"token punctuation\">(</span><span class=\"token string single-quoted-string\">'_and_'</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$method_name</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token variable\">$where</span>   <span class=\"token operator\">=</span> <span class=\"token function\">array_combine</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$columns</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$args</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n            <span class=\"token keyword\">return</span> <span class=\"token keyword static-context\">self</span><span class=\"token operator\">::</span><span class=\"token function\">find_by</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$where</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>\n  <code>find_all_by_</code>以外のメソッドには反応しないので、<br />\n  FuelPHPの他のメソッドを邪魔することはありません。\n</p>\n<h2 id=\"phpだってrailsっぽいことしたい\" style=\"position:relative;\"><a href=\"#php%E3%81%A0%E3%81%A3%E3%81%A6rails%E3%81%A3%E3%81%BD%E3%81%84%E3%81%93%E3%81%A8%E3%81%97%E3%81%9F%E3%81%84\" aria-label=\"phpだってrailsっぽいことしたい permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>PHPだってRailsっぽいことしたい</h2>\n<p>\n  Railsは数回しか触ったことがなく、特に好きも嫌いも無いんですが、\n</p>\n<ul>\n  <li>\n    PHPだと古臭いコードになる\n  </li>  \n  <li>\n    PHPイケてない\n  </li>  \n</ul>\n<p>\n  とか言われると、「意外と色々な機能あるよ」と悲しい気持ちになるので、今回の記事に至りました。\n</p>\n<p>\n  <del>確かにイケてないし</del>文法や言語仕様の欠陥はどうしようもないですが、<br />\n  今回の記事のように、Rubyちっくな機能も作れます。ダメダメではないよ！\n</p>\n<p>\n  ただ、当然ながらマジックメソッドを使用すると動作速度に影響しますし、<br />\n  あまりトリッキーなことはやらないほうが身のためかもしれません。\n</p>","timeToRead":8,"frontmatter":{"title":"phpのマジックメソッドを使ってRailsのfind_all_by_*メソッドを実装してみる","tags":["PHP","FuelPHP","Ruby","Ruby on Rails"],"date":"July 22, 2014","featuredImage":{"childImageSharp":{"fluid":{"tracedSVG":"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='400'%20height='135'%20viewBox='0%200%20400%20135'%20preserveAspectRatio='none'/%3e","aspectRatio":2.9557522123893807,"src":"/static/8f1998be299244021cf9cc0ba6b8ed48/32d53/featured-image.png","srcSet":"/static/8f1998be299244021cf9cc0ba6b8ed48/1ec58/featured-image.png 334w,\n/static/8f1998be299244021cf9cc0ba6b8ed48/32d53/featured-image.png 614w","srcWebp":"/static/8f1998be299244021cf9cc0ba6b8ed48/9b99b/featured-image.webp","srcSetWebp":"/static/8f1998be299244021cf9cc0ba6b8ed48/cd98f/featured-image.webp 334w,\n/static/8f1998be299244021cf9cc0ba6b8ed48/9b99b/featured-image.webp 614w","sizes":"(max-width: 614px) 100vw, 614px"}}}}}},"pageContext":{"slug":"/how-to-implement-find-all-by-with-php-magic-method/","previous":{"fields":{"slug":"/summary-of-webegg-2013/"},"frontmatter":{"title":"2013年 WEB EGGの振り返り","tags":["アクセス解析"]}},"next":{"fields":{"slug":"/benchmark-with-syntax-and-language-structure/"},"frontmatter":{"title":"php5.4から使える[]での配列初期化と、array()との速度比較","tags":["benchmark","PHP"]}}}},
    "staticQueryHashes": ["2585454260","2954598359"]}