PHP入門 - その他

目次

文字列をPHPスクリプトとして実行する(eval)

eval() は引数で指定した文字列を、PHPスクリプトとみなして実行します。

$str = 'echo "Hello!\n";';
eval($str);

スクリプトの末尾にデータを埋め込む

__halt_compiler()は、PHPスクリプトの解釈(コンパイル)を中止します。PHPスクリプトの末尾にデータを埋め込む際に利用されます。末尾データの先頭は、__COMPILER_HALT_OFFSET__ で参照できます。

$fp = fopen(__FILE__, "r");
fseek($fp, __COMPILER_HALT_OFFSET__);
echo stream_get_contents($fp);                    // ABCDEFG...が出力される

__halt_compiler();ABCDEFG
HIJKLMN

名前空間(namespace)

PHP5.3 で名前空間の機能が追加されました。例えば、下記のファイル構成で、A社が作成した foo ライブラリと、B社が作成した bar ライブラリでクラス名や関数名が重複していると、test.php からこれらを使用することができません。

フォルダ階層
ファイル test.php
フォルダ lib
   ファイル foo.php
   ファイル bar.php

この問題を解決するため、namespace を用いて名前空間を指定します。foo.php、bar.php を下記の様に作成します。lib と foo の間はバックスラッシュ(\)です。

namespace lib\foo;
class MyClass { function __construct() { echo "MyClass of foo\n"; } }
function MyFunction() { echo "MyFunction of foo\n"; }
const MyConst = "MyConst of foo\n";
namespace lib\bar;
class MyClass { function __construct() { echo "MyClass of bar\n"; } }
function MyFunction() { echo "MyFunction of bar\n"; }
const MyConst = "MyConst of bar\n";

こうすると、MyClass, MyFunction, MyConst などの名称は、lib\foo\MyClass, lib\foo\MyFunction, lib\foo\MyConst などのように参照することが可能となります。

require "lib/foo.php";
require "lib/bar.php";
$obj1 = new lib\foo\MyClass();
$obj2 = new lib\bar\MyClass();
lib\foo\MyFunction();
lib\bar\MyFunction();
echo lib\foo\MyConst;
echo lib\bar\MyConst;

use as を用いることで、名前空間に別名をつけることができます。下記の例では、lib\foo に対して foolib という別名をつけています。as 以降は省略可能です。

require "lib/foo.php";
require "lib/bar.php";
use lib\foo as foolib;
use lib\bar;           // use lib\bar as bar; と解釈される

$obj1 = new foolib\MyClass();
foolib\MyFunction();
echo foolib\MyConst;

$obj2 = new bar\MyClass();
bar\MyFunction();
echo bar\MyConst;

namespace { ... } の形式で名前空間を指定することもできます。名前を省略するとグローバル名前空間となります。

namespace lib\foo {
    function func() { echo "lib\\foo\\func()\n"; }
}
namespace lib\bar {
    function func() { echo "lib\\bar\\func()\n"; }
}
namespace {
    lib\foo\func();
    lib\bar\func();
}

namespace, __NAMESPACE__ は、現在の名前空間を示します。

namespace lib\foo {
    function func() { echo "lib\\foo\\func()\n"; }
}
namespace lib\bar {
    function func() { echo "lib\\bar\\func()\n"; }
}
namespace lib {
    namespace\foo\func();      // lib\foo\func()
    namespace\bar\func();      // lib\bar\func()
    echo __NAMESPACE__;        // lib
}

宣言(declare)

declare は、プログラム全般に関わる宣言を指定します。下記の2つの記述方法があります。

declare(ticks=1) {
    // この箇所に記述したプログラムに対して有効
}

declare(ticks=1);
// ファイルの末尾までのプログラムに対して有効

ticks=N は、処理系が N個の命令を実行する毎に、register_tick_function() で指定した関数を実行します。

declare(ticks=10);
register_tick_function(function() { echo "X"; });

for ($i = 0; $i < 100; $i++) {
    echo "o";                  // ooooXooooXooooXooooX....と表示される
}

encoding は、スクリプトのエンコーディングを指定します。

declare(encoding='UTF-8');

// UTF-8で記述されたプログラム...

トレイト(trait)

英語の trait は「特性」という意味を持ちます。クラスが複数の機能(特性)を継承するための仕組みです。下記の例では Foo トレイトと Baa トレイトを宣言しておき、これを Baz クラスが継承しています。

trait Foo {
    public function hello() {
        echo "Foo::Hello!\n";
    }
}

trait Baa {
    public function bye() {
        echo "Baa::Bye!\n";
    }
}

class Baz {
    use Foo, Baa;
}

$baz = new Baz();
$baz->hello();       // => Foo::Hello!
$baz->bye();         // => Baa::Bye!

複数のトレイトが同じ名前のメソッドを持つ場合エラーとなりますが、instead of を用いて Baa::hello の代わりに Foo:hello を使用することを宣言できます。また、as を用いて Baa::helloBaa::baaHello という名前で継承することもできます。

trait Foo {
    public function hello() {
        echo "Foo::Hello!\n";
    }
}

trait Baa {
    public function hello() {
      echo "Baa::Hello!\n";
    }
}

class Baz {
    use Foo, Baa {
        Foo::hello insteadof Baa;
        Baa::hello as baaHello;
    }
}

$baz = new Baz();
$baz->hello();       // => Foo::Hello!
$baz->baaHello();    // => Baa::Hello!

as private を宣言することにより、利用可能なスコープをクラス内に制限することができます。

trait Foo {
    public function hello() {
        echo "Foo: Hello!\n";
    }
}

class Baz {
    use Foo {
        hello as private;
    }

    function greet() {
        $this->hello();
    }
}

$baz = new Baz();
$baz->greet();      // => Foo::Hello!