2.

PHP で他ファイルの関数を読み込む|require_once と Composer の files

編集
この記事の要点
  • 関数を別ファイルに置いたら require_once で読み込む。読み込んだ時点で使えるようになる
  • 読み込みパスは __DIR__ 起点の絶対パスで書く。相対パスは呼び出し元によって変わる
  • 同じ関数を 2 回定義すると Fatal error_once を付けるのが基本
  • 関数はオートロードされない。クラスと違い、PSR-4 では自動では読まれない
  • Composer を使うなら autoload.files に登録する。これが唯一の自動読み込み手段

いちばん基本の形

<?php
// lib/functions.php

function taxIncluded(int $price, float $rate = 0.1): int
{
    return (int)floor($price * (1 + $rate));
}

function e(?string $s): string
{
    return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8');
}
<?php
// index.php
require_once __DIR__ . '/lib/functions.php';

echo taxIncluded(1000);      // 1100
echo e('<script>');       // &lt;script&gt;

読み込んだ関数はグローバルに登録されるので、以降どこからでも呼べます。読み込む前に呼ぶと Error: Call to undefined function になります。

4 つの読み込み文の違い

ファイルが無いとき2 回目以降
requireFatal error で停止もう一度読み込む
require_onceFatal error で停止読み込まない
includeWarning を出して続行もう一度読み込む
include_onceWarning を出して続行読み込まない

関数定義を含むファイルは require_once を使います。require だと 2 回読み込まれたときに次のエラーになります。

Fatal error: Cannot redeclare taxIncluded() (previously declared in /lib/functions.php:4)

「無くても動く」テンプレート部品なら include、「無ければ成立しない」定義なら require、と使い分けます。

パスの書き方

require_once __DIR__ . '/lib/functions.php';        // 推奨
require_once dirname(__DIR__) . '/lib/functions.php'; // 1 つ上の階層

require_once 'lib/functions.php';    // 非推奨: 呼び出し元の位置に依存する
require_once './lib/functions.php';  // 非推奨: カレントディレクトリに依存する

__DIR__ はそのファイル自身が置かれているディレクトリを返します。相対パスは「実行を開始したファイル」の位置や include_path の設定に左右されるため、cron から実行したときだけ読めない、といった問題を起こします。

戻り値を受け取る

<?php
// config.php
return [
    'db_host' => 'localhost',
    'debug'   => true,
];
$config = require __DIR__ . '/config.php';
echo $config['db_host'];        // localhost

読み込むファイルが return すると、その値が require の結果になります。設定ファイルはこの形にすると、グローバル変数を汚さずに済みます。Laravel の config/ 配下もこの仕組みです。

変数のスコープ

// view.php
echo $title;          // 読み込んだ側の変数がそのまま見える
$title = 'ページ名';
require __DIR__ . '/view.php';    // $title が見える

function render(array $data): void
{
    extract($data);                // 関数の中で読み込むと
    require __DIR__ . '/view.php'; // その関数のスコープになる
}

requireその場所のスコープをそのまま引き継ぎます。テンプレートを関数の中で読み込むと、渡した変数だけが見える状態を作れます。

二重定義を避ける

// 既に定義されていれば作らない(プラグインなど、読み込み順が読めない場合)
if (!function_exists('taxIncluded')) {
    function taxIncluded(int $price): int { /* ... */ }
}

var_dump(function_exists('taxIncluded'));   // true

ただし function_exists() で囲むのは最後の手段です。定義が 2 つ存在してどちらが使われるか分からない状態になるため、まずは require_once と読み込み位置の整理で解決してください。

名前空間の中の関数

<?php
// lib/helpers.php
namespace App\Support;

function e(?string $s): string
{
    return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8');
}
<?php
require_once __DIR__ . '/lib/helpers.php';

use function App\Support\e;      // 関数を import するときは use function

echo e('<b>');
echo \App\Support\e('<b>');   // 完全修飾でも呼べる

クラスの use と違い、関数には use function と書きます。名前空間を付けておけば、同名の関数がライブラリと衝突しません。

Composer で自動読み込みする

{
  "autoload": {
    "psr-4": { "App\\": "src/" },
    "files": ["src/helpers.php"]
  }
}
composer dump-autoload
require __DIR__ . '/vendor/autoload.php';   // これ 1 行だけ書けばよい

echo taxIncluded(1000);   // helpers.php の関数がもう使える

クラスは PSR-4 で必要になった時点で自動的に読み込まれますが、関数はその仕組みの対象外です。関数を自動で使えるようにする方法は autoload.files しかありません。ここに登録したファイルは毎リクエスト必ず読み込まれるので、重い処理を書かないでください。

関数ファイルを分けるときの指針

  • 1 ファイルにまとめすぎない。用途ごとに分けるstring.php date.php など)
  • ファイルの先頭以外に echo や実行文を書かない。読み込んだだけで副作用が出る
  • 関連する関数が 3 つ以上になったらクラスにまとめることを検討する(オートロードが効く)
  • 汎用の名前(format() get())は避ける。名前空間を付けるか接頭辞を付ける

関連

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 関数の定義と呼び出し方法
  2. 他ファイルの関数読み込み
  3. 可変長引数

最近更新/作成されたページ