PHP8で新たに追加されたStringableインタフェースは、オブジェクトから文字列へ変換するクラスに強制的になります。
強制して無理やりデータ型をstringにするので型チェックしているのと同じになるという機能。
このインタフェースを実装するクラスは __toString() メソッドを用意するだけのシンプルな作り。
Stringableを実装したクラスのサンプル
Stringableインタフェースをimplementsしたクラスはかんたんなので、いきなりクラスの内容から見てみましょう。
class Test implements Stringable
{
private $val1;
private $val2;
private $val3;
public function __construct($val1, $val2, $val3)
{
$this->val1 = $val1;
$this->val2 = $val2;
$this->val3 = $val3;
}
public function __toString(): string
{
return sprintf('%s, %s, %s', $this->val1, $this->val2, $this->val3);
}
}
$val = new Test(1, 2, 3);
var_dump($val);
echo $val;
echo PHP_EOL;
print $val;
echo PHP_EOL;
var_dump('change to string: ' . $val);
var_dump(sprintf('sprintf: %s', $val));
object(Test)#1 (3) {
["val1":"Test":private]=>
int(1)
["val2":"Test":private]=>
int(2)
["val3":"Test":private]=>
int(3)
}
1, 2, 3
1, 2, 3
string(25) "change to string: 1, 2, 3"
string(16) "sprintf: 1, 2, 3"
Stringableは __toString() の実装を強制する
Stringableインタフェースの中身はシンプルです。__toString() メソッドの実装をクラスに強制するだけ。
このメソッドは名前の通り、文字列を返すようにしてください。
戻り値の型をstring以外にして処理を実行すると Fatal Error(致命的なエラー)になります。
public function __toString(): int
{
return sprintf('%s, %s, %s', $this->val1, $this->val2, $this->val3);
}
PHP Fatal error: Test::__toString(): Return type must be string when declared in /home/vagrant/php-test.php on line 14
そもそもこのインタフェースでは __toString() の戻り値の型まで指定されているので、string以外は指定できません。
動かして確かめるまでもなく、phpcsなどの静的コードチェックで構文エラーになります。
Test::__toString(): Return type must be string when declared
ただし注意が必要なのは、メソッドの戻り値の型の未指定では構文エラーになりません。
このとき処理を動かすと、型がstring以外はstring型にキャストします。
(キャストできないものは警告・エラーになる。)
public function __toString()
{
return $this->val1 + $this->val2 + $this->val3;
}
object(Test)#1 (3) {
["val1":"Test":private]=>
int(1)
["val2":"Test":private]=>
int(2)
["val3":"Test":private]=>
int(3)
}
6
6
string(19) "change to string: 6"
string(10) "sprintf: 6"
動かないと分からないコードはよろしくないし、PHP8からは型の厳密化が進んでいるので型を指定しましょう。
__toString() はマジックメソッド。直接コールできない。
__toString()は、メソッド名の頭に '__' がついているので直接コールはできません。これをマジックメソッドといいます。
(コンストラクタがその代表例。)
__toString() が起動するタイミングは、クラスインスタンスを文字列として扱ったときや、echo, printで出力するときです。
それ以外は発動しません。
さっきからサンプルコードの処理結果で不思議に思ったでしょう。
var_dump() で出力したときはクラスオブジェクトなのに、 echo, printではインタンスをそのまんま出力しているのに、__toString()の結果が出ているから。
これが Stringableインタフェースの真骨頂です。というかこれ以外の機能はない。
ちょっとひねって、こういうときも__toString() が発動します。
var_dump((string)$val);
string(7) "1, 2, 3"
PHP公式ドキュメント
クラスオブジェクトはクラスオブジェクト。データ型が変わるわけじゃない。
クラスインスタンスはあくまでクラスインスタンスなので、文字列として扱ったあともその状態は保持します。
var_dump($val);
echo 'change to string: ' . $val . PHP_EOL;
var_dump($val);
object(Test)#1 (3) {
["val1":"Test":private]=>
int(1)
["val2":"Test":private]=>
int(2)
["val3":"Test":private]=>
int(3)
}
change to string: 1, 2, 3
object(Test)#1 (3) {
["val1":"Test":private]=>
int(1)
["val2":"Test":private]=>
int(2)
["val3":"Test":private]=>
int(3)
}
PHP公式ドキュメント