Quantcast
Channel: PHP7.4タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 113

PHPのCallableについて完全に理解する

$
0
0

はじめに

Callableという擬似型は PHP 5.4系で導入されていたようなのですが、ある値が Callableかどうかがどのように決まるのかさっぱり理解できず、業務で使う機会もそんなになかったことから放置していました。

業務で使う機会が出てきたというわけでも全くもって全くないのですが、ふと考えてみたら完全に理解できた気がしてしまったので、ツッコミ覚悟で記事にまとめることにしました。

この記事ではどんな値を is_callable()に渡したら trueを返されるのかを探っていきます。 is_callable()trueを返す値はそのまま call_user_func() , call_user_func_array()などに渡して呼び出すことが可能です。

var_dump()を含んだコードの動作確認は paiza.IOで行っています。執筆時のPHPバージョンは PHP 7.4.1でした。

この記事のスコープ外

「関数やクラスがどの時点で定義されるのか」というのは、これはこれで複雑な話題です。

この記事では、「関数やクラスが定義されているかどうか」を明確にした上で Callableかどうかの判定方法を理解したいため、関数やクラスの定義方法は最もシンプルなもののみを用います。

<?php// シンプルな関数定義functionsomeFunction(){}// シンプルなクラス定義classSomeClass(){publicstaticfuncionSomeClassMethod(){}publicfunctionSomeObjectMethod(){}}// シンプルでない関数定義たちif(true){functionanotherFunction(){}}functiondefineYetAnotherFunction(){functionyetAnotherFunction(){}}// シンプルでないクラス定義たちif(true){classAnotherClass(){publicstaticfuncionAnotherClassMethod(){}publicfunctionAnotherObjectMethod(){}}}functiondefineYetAnotherClass(){classYetAnotherClass(){publicstaticfuncionYetAnotherClassMethod(){}publicfunctionYetAnotherObjectMethod(){}}}

::を含まない文字列

文字列と同じ名前の関数が定義されている場合は Callableであり、そうでない場合は Callableでない、と判定されます。

<?phpfunctionis_odd(int$int):bool{return$int%2===1;}var_dump(is_callable('is_odd'));// => bool(true)var_dump(is_callable('is_even'));// => bool(false)

::の両側になんかある文字列

::の左側の文字列と同じ名前のクラスが定義されていて、かつ ::の右側の文字列と同じ名前のメソッドが定義されていて publicな場合は Callableであり、そうでない場合は Callableでないと判定されます。

<?phpclassSomeClass{publicstaticfunctionsomePublicClassMethod(){}protectedstaticfunctionsomeProtectedClassMethod(){}privatestaticfunctionsomePrivateClassMethod(){}publicfunctionsomePublicObjectMethod(){}protectedfunctionsomeProtectedObjectMethod(){}privatefunctionsomePrivateObjectMethod(){}}var_dump(is_callable('SomeClass::somePublicClassMethod'));// => bool(true)var_dump(is_callable('SomeClass::someProtectedClassMethod'));// => bool(false)var_dump(is_callable('SomeClass::somePrivateClassMethod'));// => bool(false)var_dump(is_callable('SomeClass::somePublicObjectMethod'));// => bool(true)var_dump(is_callable('SomeClass::someProtectedObjectMethod'));// => bool(false)var_dump(is_callable('SomeClass::somePrivateObjectMethod'));// => bool(false)var_dump(is_callable('AnotherClass::somePublicClassMethod'));// => bool(false)var_dump(is_callable('AnotherClass::somePublicObjectMethod'));// => bool(false)var_dump(is_callable('SomeClass::anotherPublicClassMethod'));// => bool(false)var_dump(is_callable('SomeClass::anotherPublicObjectMethod'));// => bool(false)

クラスのメソッド内で Callableかどうかを判定する場合、 ::の左側の文字列には追加で self , parentが許可され、 ::の右側の文字列には追加で protected , privateなメソッドの名前が許可されます。

<?phpclassParentClass{publicstaticfunctionsomePublicClassMethod(){}publicfunctionsomePublicObjectMethod(){}}classSomeClassextendsParentClass{publicstaticfunctionclassMethod(){var_dump(is_callable('SomeClass::somePublicClassMethod'));// => bool(true)var_dump(is_callable('self::somePublicClassMethod'));// => bool(true)var_dump(is_callable('parent::somePublicClassMethod'));// => bool(true)var_dump(is_callable('SomeClass::someProtectedClassMethod'));// => bool(true)var_dump(is_callable('SomeClass::somePrivateClassMethod'));// => bool(true)var_dump(is_callable('SomeClass::somePublicObjectMethod'));// => bool(true)var_dump(is_callable('self::somePublicObjectMethod'));// => bool(true)var_dump(is_callable('parent::somePublicObjectMethod'));// => bool(true)var_dump(is_callable('SomeClass::someProtectedObjectMethod'));// => bool(true)var_dump(is_callable('SomeClass::somePrivateObjectMethod'));// => bool(true)}publicstaticfunctionsomePublicClassMethod(){}protectedstaticfunctionsomeProtectedClassMethod(){}privatestaticfunctionsomePrivateClassMethod(){}publicfunctionobjectMethod(){var_dump(is_callable('SomeClass::somePublicClassMethod'));// => bool(true)var_dump(is_callable('self::somePublicClassMethod'));// => bool(true)var_dump(is_callable('parent::somePublicClassMethod'));// => bool(true)var_dump(is_callable('SomeClass::someProtectedClassMethod'));// => bool(true)var_dump(is_callable('SomeClass::somePrivateClassMethod'));// => bool(true)var_dump(is_callable('SomeClass::somePublicObjectMethod'));// => bool(true)var_dump(is_callable('self::somePublicObjectMethod'));// => bool(true)var_dump(is_callable('parent::somePublicObjectMethod'));// => bool(true)var_dump(is_callable('SomeClass::someProtectedObjectMethod'));// => bool(true)var_dump(is_callable('SomeClass::somePrivateObjectMethod'));// => bool(true)}publicfunctionsomePublicObjectMethod(){}protectedfunctionsomeProtectedObjectMethod(){}privatefunctionsomePrivateObjectMethod(){}}SomeClass::classMethod();(newSomeClass())->objectMethod();

Closureオブジェクト

無名関数式を使って作成した Closureオブジェクトは Callableと判定されます。

<?phpvar_dump(is_callable(function():bool{returntrue;}));// => bool(true)

__invoke()を実装したオブジェクト

public function __invoke()を実装したオブジェクトは Callableと判定されます。

<?phpvar_dump(is_callable(newclass(){publicfunction__invoke():bool{returntrue;}}));// => bool(true)

[クラス名, ::を含まない文字列]

※力尽きたので一旦記事は公開する

[クラス名, ::の両側になんかある文字列]

※力尽きたので一旦記事は公開する

[オブジェクト, ::を含まない文字列]

※力尽きたので一旦記事は公開する

[オブジェクト, ::の両側になんかある文字列]

※力尽きたので一旦記事は公開する


Viewing all articles
Browse latest Browse all 113

Trending Articles