Foo\Bar\Buz
クラスのインスタンスから"Buz"
を求める関数です。
いろんな実装方法があるのですが、結論から言うと読みやすさと速さの観点から(new \ReflectionClass($obj))->getShortName()
が一番良さそうです。
実装1: クラス名をファイルパスに見立ててbasenameで調べるhackeyなパターン
namespace Foo;
class Bar {}
function get_simple_name1($obj) {
return basename(strtr(get_class($obj), '\\', '/'));
}
assert(get_simple_name1(new \Foo\Bar) === 'Bar');
assert(get_simple_name1(new \Exception) === 'Exception');
実装2: 一度配列にして取り出すパターン
function get_simple_name2($obj) {
return array_slice(explode('\\', get_class($obj)), -1)[0];
}
assert(get_simple_name2(new \Foo\Bar) === 'Bar');
assert(get_simple_name2(new \Exception) === 'Exception');
実装3: リフレクションで調べるパターン
function get_simple_name3($obj) {
return (new \ReflectionClass($obj))->getShortName();
}
assert(get_simple_name3(new \Foo\Bar) === 'Bar');
assert(get_simple_name3(new \Exception) === 'Exception');
実装4: 文字列のオフセットで切り取るパターン
function get_simple_name4($obj) {
$class = get_class($obj);
return substr($class, -strrpos($class, '\\'));
}
assert(get_simple_name4(new \Foo\Bar) === 'Bar');
assert(get_simple_name4(new \Exception) === 'Exception');
速さのベンチマーク
どれが良いかよくわからないので、速度を比較してみる。
function benchmark($name, callable $test) {
$start = microtime(true);
for ($i = 0; $i < 100000; $i += 1) $test();
echo $name, ': ', microtime(true) - $start, PHP_EOL;
}
$obj = new \Foo\Bar;
benchmark('get_simple_name1', function() use ($obj) {
get_simple_name1($obj);
});
benchmark('get_simple_name2', function() use ($obj) {
get_simple_name2($obj);
});
benchmark('get_simple_name3', function() use ($obj) {
get_simple_name3($obj);
});
benchmark('get_simple_name4', function() use ($obj) {
get_simple_name4($obj);
});
結果は、リフレクションが一番早いけれど、有意差があるかは不明だが、。get_class
が遅いんじゃないかという仮説がたちました
get_simple_name1: 0.41280698776245
get_simple_name2: 0.42476606369019
get_simple_name3: 0.39611792564392
get_simple_name4: 0.41671085357666
get_class
はリフレクションより早かったです。
$obj = new \Foo\Bar;
benchmark('get_class', function() use ($obj) {
get_class($obj);
});
benchmark('ReflectionClass', function() use ($obj) {
(new \ReflectionClass($obj))->getShortName();
});
get_class: 0.15777897834778
ReflectionClass: 0.31506705284119