PHP library

提供:senooken JP Wiki

Framework

  • Symfony
  • CakePHP
  • FuelPHP: 2010年誕生。
  • Codeigniter: シンプル、軽量。
  • Zend
  • Laravel: 2011年誕生。
  • Phalcon: 高速で有名。
  • Yii - Wikipedia
 素直にPhalconを使うのが安定ではないか?ああ、C拡張が必要だから、共用サーバーへのインストールで困る。

Directory

https://chatgpt.com/c/67bd2c93-ee1c-800b-b4ff-d40a326dcf0c

MVC系の画面の場合、Controllerの共通処理 (Service) は、classやService系のディレクトリーに配置する。

act/action系のディレクトリーは、ユーザーアクセスやルーティングと紐づいているのでここにあまり入れない。

テンプレート系のVewファイルはincludeやlayoutなどの専用のディレクトリーに格納するなど。

Template

いろいろある。

  • Blade: Laravel標準。
  • DIV: 1ファイルでシンプル。大規模には向かない。
  • Smarty: 万能。
  • Twig: 拡張はしにくい。
 使うとしたら、歴史の長いSmarty。

高速らしい。

そもそもテンプレートエンジンがいるのかどうかという議論がある。

UI/UXを突き詰めると、JavaScriptを使わざるを得ず、サーバーテンプレートエンジンは初回だけなので、いっそのことJSで全部やろうというのが最近の流れの模様。

PHP自体が一種のテンプレートエンジンという主張がある。が、関数をあれこれ書く必要があり、可読性が悪い。

SmartyよりTwigのほうが性能が上とか。

Volt: テンプレートエンジン — Phalcon 3.0.2 ドキュメント (Japanese / 日本語)」。高速フレームワークのPhalconではVoltを使っている。

Twig

Twig v3のほうが速いらしいが、Smarty v3のほうが速いというデータもある。

Smarty

Pure PHP/HTML views VS template engines views - Stack Overflow」が決定的だった。Smartyの開発者がSmartyのほうがTwigより速いと回答していた。2012年。Smartyでいいと思う。

カスタムタグ

https://chatgpt.com/c/6789e2f7-6df0-800b-ac87-2254034abd4e

関数プラグイン{function}とブロックプラグイン{block}の2種類で独自のタグを定義できる。

{function} - Smarty Documentation

{block} - Smarty Documentation

デフォルトのプラグインディレクトリー (plugins) にfunciton.<function-name>.phpとして保存して使う。

2. Basic Syntax

Embedding Vars in Double Quotes

Embedding Vars in Double Quotes | Smarty

Smartyは二重引用符内で、assigned variableを認識する。その都合、変数名は数字、文字、_のみが許容される。

ピリオド.やオブジェクト演算子->などは、その都合でバックチック``で囲む必要がある。

Smarty v3では、二重引用符内でタグも許容する。これは、修飾子付きの変数などで便利だ。

バックチックは二重引用符とセットで使う。変数で.や->がある場合の認識用。{}ではない。

Conditional operator

Ternary operators · smarty-php/smarty · Discussion #660

  • {($foo) ? $var1 : $var2}
  • {$myvar|default:"foobar"}`
  • {if $myvar}was set{else}not set{/if}

Smarty v5から条件演算子に対応している。ただし、評価部分は丸括弧が必要。公式文書で文書化はされていないらしい。

v5以前だと工夫が必要。|defaultでやるのがいいとか。ただし、これは変数が空のときだけ。{$myvar?:'N/A'}相当は|defaultで代替できる。

Logical operator

Smarty v2では、Smartyの関数の引数部分では、論理演算子が使えない。{if}だと使えるのだが。しかたないので、専用の変数を用意する。

7. Builtin-in Functions

{assign}

Chapter 8. Custom Functions | Smarty

template内で変数を割り当てする。

{assign var='name' value='Bob'}

The value of $name is {$name}.

https://chatgpt.com/c/67a0393a-9920-800b-805a-1c344febfdc2

ただし、Smarty v2のassignは配列リテラルの代入はできない。工夫が必要。

一番簡単なのはexplode修飾子。

{assign var="fruits" value="apple,banana,cherry"|explode:","}

他にはappendや

{append var="fruits" value="Apple"}
{append var="fruits" value="Banana"}
{append var="fruits" value="Cherry"}

空の配列を作って、キーを指定して追加。

{assign var="fruits" value=""} {* まず空の配列を作成 *}

{assign var="fruits.apple" value="Apple"}
{assign var="fruits.banana" value="Banana"}
{assign var="fruits.cherry" value="Cherry"}

根本的にはPHP側で変数で用意しておくのがよい。

{capture}

{capture} | Smarty

ブロック内を変数に押し込めるための機能。

{capture name="<name>"}
{/capture}

nameで指定した<name>にcapture内が入る。

nameを指定しない場合、defaultとみなされる。

  • name
  • assign
  • append

特にappendのパラメーターが重要。これを使うことでcssやjsを共通のheaderの共通部分に押し込める。

captureの内容を参照する場合は、$smarty.capture.<name>で参照する。

capture appendで変数名を指定する。Smarty 3.1からはこの変数が自動結合されている。

3.1未満の場合、配列になっているので使う際にforeachなどが必要。

https://chatgpt.com/c/67cab73d-0878-800b-b3ec-766c42eaf42b

なお、capture内で変数を使っている場合、captureブロック定義時に固定される。$smarty.capture.<name>を使う際に、引き渡したい場合、evalのような工夫が必要になる。

あるいは、他に以下の方法がある。

  • if/assign: 短いテキストだけが変わる場合、if/assignでそこだけ変数で可変にするのもいい。
  • capture: if/assignのassign部分が複数行の場合に有効。
  • replace: captureした文章の一部分だけを変更する場合。
{fetch}

{fetch} | Smarty

指定したファイルを取得してそれをそのまま表示する。

{foreach}

Smarty v3からcontinue/breakが登場。

{foreach from=<array> item=<element> key=<key> name=<prop>}

nameはSmarty v2専用。foreachのプロパティーへのアクセスに必要。

  • index
  • iteration
  • first
  • last
  • show
  • total

name=fooのとき、$smarty.foreach.foo.last}のようにして、foreach内でforeachのプロパティーにアクセスできる。

ただし、Smarty v3から構文が変わった。name=は使わない方がよさそう。

{if},{elseif},{else}

{if},{elseif},{else} | Smarty

{literal}

https://chatgpt.com/c/6799d1f8-dd54-800b-a5cc-b22c453083fb

{などはSmartyのタグとして解釈される部分では解釈される。CSSやJavaScriptなどで{をそのまま使いたい場合、{literal}タグで解釈を阻止できる。

ただ、{literal}が不要なケースもある。capture/block内。これらがliteral相当の機能がある。

{strip}

{strip} | Smarty

tpl内の空白空行を除去して1行でHTMLを表示する。tpl内のコードの可読性を確保しながら、結果に余計な空白を作らない。

html要素の前後を{strip}で囲むのが基本的な使用方法。

{* the following will be all run into one line upon output *}
{strip}
<table border='0'>
 <tr>
  <td>
   <a href="{$url}">
    <font color="red">This is a test</font>
   </a>
  </td>
 </tr>
</table>
{/strip}

なお、{strip}は変数には影響を与えない。変数内に作用したければ、strip修飾子を使う。

Advanced feature

Template inheritance
About

継承により、オブジェクト指向プログラミングの概念をテンプレートに取り込める。ただし、block/extendsはSmarty v3.0からしか使えない。v2ではincludeやcaptureを駆使するしかない。

子テンプレートで拡張可能な基本テンプレートを定義できる。拡張は、子テンプレート親の名前付きブロック領域の上書きを意味する。

  • 子テンプレートは、blockタグ内しか記述できず、blockタグ以外は削除される。
  • blockタグの内容は、append/prependオプションでマージ可能。または、$smarty.block.parent/$smarty.block.childのプレースホルダーを使える。
  • テンプレート継承は、コンパイル時に単一のコンパイル済みテンプレートを作成する。includeよりもパフォーマンスが大幅に向上する。
  • 子テンプレートは先頭でextendsタグで親を指定して、拡張する。extendsタグの他に、PHPでfetch/display指定時にextendsを指定することでもできる。

イメージ。

// layout.tpl
<html>
<head>
  <title>{block name=title}Default Page Title{/block}</title>
  {block name=head}{/block}
</head>
<body>
{block name=body}{/block}
</body>
</html>
// myproject.tpl

{extends file='layout.tpl'}
{block name=head}
  <link href="/css/mypage.css" rel="stylesheet" type="text/css"/>
  <script src="/js/mypage.js"></script>
{/block}
// mypage.tpl
{extends file='myproject.tpl'}
{block name=title}My Page Title{/block}
{block name=head}
  <link href="/css/mypage.css" rel="stylesheet" type="text/css"/>
  <script src="/js/mypage.js"></script>
{/block}
{block name=body}My HTML Page Body goes here{/block}

描画結果は以下。

<html>
<head>
  <title>My Page Title</title>
  <link href="/css/mypage.css" rel="stylesheet" type="text/css"/>
  <script src="/js/mypage.js"></script>
</head>
<body>
My HTML Page Body goes here
</body>
</html>

継承関係で使うタグ

  • block
  • extends
  • include
  • insert: ただし非推奨。

なお、extendsした場合、子テンプレートで入力内容を表示させるには、基本的にblockを使うしかない。親の変数にassignで代入して表示することは一応できる。それ以外は無視されて表示されない。

{block}

{block} | Smarty

blockで追記の記法がいくつかあるので注意が必要。基本は、$smarty.block.childを親側に配置だと思う。

  • prepend
  • append
  • $smarty.block.child
  • $smarty.block.parent

prependとappendはparentを中心に考える。appendは子の後ろに親を追加する。子側でオプション指定が必要になる。

上書きと追記を子で切り替えられる利点はあるが、上書きすることないなら、childを親に配置したほうがわかりやすい。

{extends}

{extends} | Smarty

{include}

{include} | Smarty

外部のtplファイルを読み込める。Smarty v2までだとこれを使うしかない。

{include file='links.tpl' title='Newest links' links=$link_array}

fileだけ必須。他はvar=value形式で、変数をinclude先に渡せる。

{include file='common.tpl' value="`$app.var1` `$app.var2`"}

変数名はなんでもいいが、こだわりがないならvalueでいい気がする。assignなどでも共通だし。

引数で連結したい場合、""と``を組み合わせる。

Smarty v2

block/extendsはSmarty v3.0から導入された。v2で似たような継承を使った共通化には工夫が必要になる。

include/captureを駆使して実現する。captureで定義した変数は、定義後しか使用できない。capture変数を定義前は参照できない。したがって、以下の順序で指令を使う。

  1. capture定義
  2. includeでcapture変数引き渡し

さらに、以下のロジックで末端の定義変数を全体のテンプレートで最後に全部参照できるようにする。

  1. 画面固有.tpl
  2. 共通.tpl
  3. 全体.tpl

captureで定義してからしか変数を参照できないので、以下の順番でincludeの階層関係を作って、末端の変数が全体で参照できるようにする。

Other

Version

https://chatgpt.com/c/6799d1f8-dd54-800b-a5cc-b22c453083fb

// .tpl
{$smarty.version}
phpinfo();
require_once('libs/Smarty.class.php');

$smarty = new Smarty();
echo 'Smarty Version: ' . $smarty->getVersion();
CSSのコンポーネント

Smartyでコンポーネント単位でCSSを適用したい。

https://chatgpt.com/c/6799d1f8-dd54-800b-a5cc-b22c453083fb

CSSはhead要素のstyleに置くしかないのをどうにか1ファイル単位で管理したい。

できれば1個のtplファイルでHTML/CSS/JSをコンポーネントとして扱えるといい。最悪インラインCSSでも。

AIに質問したら、CSSだけのファイルをtplに固めてheader.tplでhead要素内に配置するといういまいちな回答。

  • captureでglobalヘッダーに追記。
  • block
  • assignで変数に設定。

captureとblockがいい。appendでスタイルを追記できる。

extendsしているならblockでいい。extendsしていなくてincludeでやっているなら、captureでやる。

    <style>
        {foreach from=$styles item=style}
            {$style}
        {/foreach}
    </style>
{capture append='styles'}{literal}
.js_marquee_challenge_title {
    position: relative;
    width: 260px;
    height: 33px;
    margin: 0 auto;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
{/literal}{/capture}

smarty v2だと配列になるのでforeachでやる。

captureが{を解釈するのでliteralでやる。

問題。base.tplでheader.tplとcomponent.tplをincludeすると、component.tplの変数がheader.tplに反映されない。

  1. postfilterでbody以下に登場するstyle/cssをheadの直前に配置するなどする。
  2. インラインCSSで対応。

インラインCSSで対応できる分はこれで対応したらいいと思う。インラインCSSでどうにもできないケースになったら、そのときに考える。

最悪、JavaScriptでstyle要素を追記して対応する。JavaScriptに依存するのであまりよくないが、最悪これでなんとでもなる。

Pagination

Smarty自体にはページネーション用の機能はない。自分で作る。

ORM

Ref:

いろいろある。Doctrineが有名。

  • Doctrine: Symfonyで採用。有名。
  • Eloquent
  • Propel: Symfony v1.2で採用されていた。
  • PHP activerecord
  • PHPDAO
  • PDO: PHP標準。
  • Xyster
 ただ、速度を優先する場合、PDOが最速になるらしい。

ORMは別になくてもいいか。いや、validateなどでほしいか。

ChatGPT: PHPのORMで最高速なのはどれ?


PHPのORMで「最高速」を目指す場合、目的やデータ量、柔軟性や機能性のニーズによって適切な選択肢が変わります。ただ、以下は一般的に高速性が評価されているORMやアプローチです。

      1. 1. **Cycle ORM**

- **概要**: Cycle ORMは、PHP向けに軽量で高性能なORMとして設計されており、メモリ使用量やクエリ生成において優れた最適化がなされています。また、`DataMapper`パターンを採用しており、柔軟性が高く、複雑なデータ構造にも対応可能です。

- **特徴**:

- メモリ効率が良く、データベースへのアクセスが高速。

- マッピング定義が柔軟で、データベーススキーマの同期などの管理機能も備えている。

- **適合するケース**: 高速性が求められるが、複雑なデータ構造やリレーションも必要な場合。

- **URL**: [Cycle ORM](https://cycle-orm.dev/)

      1. 2. **Doctrine ORM(高度に最適化した場合)**

- **概要**: Doctrineは多機能で、エンタープライズレベルのアプリケーションにも使用されていますが、設定やキャッシュの適切な調整で高速化が可能です。Doctrineは大規模なデータベースや複雑なエンティティ構造を扱うことを得意としており、クエリキャッシュやメタデータキャッシュを活用すると、高速なクエリ処理が実現できます。

- **特徴**:

- キャッシュ(メタデータ、クエリ、結果)を駆使することでパフォーマンスが向上。

- バッチ処理やフェッチモードの調整により、余分なSQLクエリを抑制できる。

- **適合するケース**: 大規模なアプリケーションで、柔軟性や機能性と高速性のバランスが求められる場合。

- **URL**: [Doctrine ORM](https://www.doctrine-project.org/projects/orm.html)

      1. 3. **Eloquent ORM(軽量化する場合)**

- **概要**: Eloquentは、Laravelの標準ORMで、柔軟で書きやすいAPIを提供しています。ただし、Eloquentは`Active Record`パターンを採用しているため、大量のデータや複雑なクエリには向きません。しかし、シンプルなアプリケーションであれば、十分な速度を発揮できます。

- **特徴**:

- データベースアクセスが少ないケースで非常に簡便で高パフォーマンス。

- 適切なスコープやクエリビルダーを利用することで高速なデータアクセスが可能。

- **適合するケース**: シンプルなアプリケーションで、多少の軽量化(不必要なEloquentモデルの削除など)を行い、APIの利便性と速度を両立したい場合。

- **URL**: [Eloquent ORM](https://laravel.com/docs/eloquent)

      1. 4. **直接的なクエリビルダー使用(PDO, Laminas DBなど)**

- **概要**: ORMを使わず、PDOやクエリビルダー(Laminas DBなど)を用いて、データベースと直接やり取りすることも非常に高速な手法です。ORMのオーバーヘッドがないため、特にトランザクション内での多くのデータ操作が求められる場合や、複雑なクエリが必要な場面では、これが最速のアプローチです。

- **特徴**:

- ORMを介さず直接データベースを操作するため、最小限のオーバーヘッドで済む。

- 柔軟で高度なクエリやバッチ操作も容易。

- **適合するケース**: 速度重視の大規模アプリケーションや、複雑なクエリが必要なケース。

これらを総合的に考えると、 **「Cycle ORM」** が最もバランスよく高性能を発揮しやすく、ORMの利便性を保持しながらも高速なデータ操作が可能です。しかし、最高速を求めるのであれば、ORMを使わずにクエリビルダーやPDOを直接活用することが理想的です。

Cycle ORMが安定して速いらしい。これでいくか。

Migrate

PHPで「Doctrine Migrations」を使ってみる

CakePHPに採用されているPhinxのほうが人気なのでPhinxを使ったほうがよいだろう。

ORMとあわせたほうがいいかも。

Test

  • PHPUnit

Search

検索キーワードをフォームから受信後、DBにSQLで検索をかけて取得結果を返すのが基本。

それとは別に、検索用のアプリにリクエストを受け渡しして検索するという方法がある。どちらでもいけるような、ドライバーのライブラリーがある。

検索サービスで有名なのは以下。

 Laravel Scoutでtntsearchを使う方法がある (Laravel Scout + TNTSearchによる小規模プロジェクトへの全文検索機能の追加 #PHP - Qiita/Laravel ScoutとTNTSearchを使用してサイト全文検索を実装してみる – helog)。

Packagist」の検索結果をみても、tntsearchが特に人気の模様。

PEAR

About

PEAR - Wikipedia

PEAR (PHP Extension and Application Repository, ペア)

PHPで利用可能なライブラリーを提供しているサービス。PEARはPHPで書かれたライブラリー。PECLはC言語の拡張ライブラリー (extension)。

PHP 5までPHP本体に同梱されていた。

準標準ライブラリー。名前空間なしで見知らぬクラス名が登場したらPEARの可能性がある。

Directory

Pearのインストール場所 - めも帖

PEAR同梱のpear config-showで各種インストールディレクトリーがわかる。

特に重要なのが、php_dir (=/usr/share/pear or php)。ここにPEARのPHPファイルやクラス定義がある。シンボル参照などで重要。