PHP
Require
Require_once

PHPのrequireが僕の思った動作ではなかったお話

同僚にPHPの質問をされて、あれって思って調べてみたら僕の思ったrequireの動作とは違ったので、それを記事にして皆さんにお伝えします。

まず、以下のコードが実行できない。

  • index.php
  • req1.php
  • req2.php

という3つのPHPファイルがあります。

index.php
<?php

ini_set('display_errors', "On");

require 'req1.php';
require 'req2.php';

echo 'hello<br>';
echo sayHello();
echo sayHello2();
req1.php
<?php

require 'req2.php';

function sayHello() {
    return "called sayHello<br>" . sayHello2();
}
req2.php
<?php

function sayHello2() {
    return "called sayHello2!<br>";
}

ここで重要なのは、req2.phprequireしているのはindex.phpreq1.phpの2つのPHPファイルだということです。

これを実行してみると、以下のエラーが出ます。

Fatal error: Cannot redeclare sayHello2() (previously declared in /xxxxxx/test.php:4) in /xxxxxx/req2.php on line 5

どうやら、sayHello2が複数回宣言されているためエラーしているようです。ですが、複数回sayHello2を宣言した覚えはありません!

原因は、requireにあった

まず、test.phpreq1.phpreq2.phpをrequireすることで、以下のように変換されるはずです。

test.php
<?php

ini_set('display_errors', "On");

//require 'req1.php';
require 'req2.php';

function sayHello() {
    return "called sayHello<br>" . sayHello2();
}

//require 'req2.php';
function sayHello2() {
    return "called sayHello2!<br>";
}

echo 'hello<br>';
echo sayHello();
echo sayHello2();

この状態ではまだrequire 'req2.php';が残っているので、それもrequireすると、

test.php
<?php

ini_set('display_errors', "On");

//require 'req1.php';
//require 'req2.php';
function sayHello2() {
    return "called sayHello2!<br>";
}

function sayHello() {
    return "called sayHello<br>" . sayHello2();
}


//require 'req2.php';
function sayHello2() {
    return "called sayHello2!<br>";
}

echo 'hello<br>';
echo sayHello();
echo sayHello2();

といった状態になるはずです。こうしてみると、test.php内にsayHello2関数が2つも宣言されていますね。これではエラーするのも当然です。

require_onceを使えば解決

ではどうやってこの問題を解決すればいいかと言いますと、require_onceを使って一度だけしかPHPファイルを読み込めないようにします。

test.php
<?php

ini_set('display_errors', "On");

require_once 'req1.php';
require_once 'req2.php';

echo 'hello<br>';
echo sayHello();

echo sayHello2();
req1.php
<?php

require_once 'req2.php';

function sayHello() {
    return "called sayHello<br>" . sayHello2();
}
req2.php
<?php

function sayHello2() {
    return "called sayHello2!<br>";
}

としてtest.phpを実行してみるとエラーなく実行されて、以下のように表示されます。

hello
called sayHello
called sayHello2!
called sayHello2!

require_onceがうまくいく理由

先ほどのように、require_onceした時にPHPの文がどのように展開されるかを見れば理解できると思います。

まず、test.phpreq1.phpreq2.phpをrequireします。

test.php
<?php

ini_set('display_errors', "On");

//require_once 'req1.php';
require_once 'req2.php';

function sayHello() {
    return "called sayHello<br>" . sayHello2();
}

//require_once 'req2.php';
function sayHello2() {
    return "called sayHello2!<br>";
}

echo 'hello<br>';
echo sayHello();
echo sayHello2();

で、この次にrequire_once 'req2.php';が実行されると思いきや、既にreq2.phprequire済みなので再度読み込みはしません。

よって、sayHello2関数は一回だけしか宣言されないのでこのプログラムは正しく実行できます!

結論

require_onceを使いましょう!

参考

require(公式ドキュメント)
require_once(公式ドキュメント)