简体   繁体   English

调用前检查某项是否为函数

[英]Check if something is a function before calling it

I have a class that looks a bit like this: 我有一堂课,看起来像这样:

<?php

namespace App\Http\Controllers;

use Exception;
use Illuminate\Http\Request;

class FormatAddressController extends Controller
{
    public function __construct()
    {
        $this->middleware(['api-auth']);
        $this->middleware(['api-after']);
    }

    public function format(Request $request) {
        // TODO first, get customer settings to see what functions to run, and how to run them
        // but, assume that the settings come as an array where the key is the function name
        // and the value is one of NULL, false, or settings to pass through to the function
        $settings = ['isoAndCountry' => true, 'testFunc' => ['testSetting' => 'test setting value']];

        $address = $request->input('address');

        $errors = [];

        foreach ($settings as $funcName => $funcSettings) {    
            try {
                $address = $this->$funcName($funcSettings, $address); // every function has to return the modified address
            } catch(Exception $e) {
                $errors[$funcName] = $e;
            }

        }

        return response()->json([
            'address' => $address,
            'errors' => $errors
        ]);
    }

    public function isoAndCountry($settings, $address) {
        // TODO

        return $address;
    }
}

Now, when I call this function, isoAndCountry, through that settings loop I defined above, it works! 现在,当我通过上面定义的设置循环调用此函数isoAndCountry时,它起作用了! It works just fine. 它工作正常。

However I tried following this thread and checking is_callable and... it errors: 但是我尝试遵循此线程并检查is_callable和...错误:

            if (is_callable($this->$funcName)) {
                try {
                    $address = $this->$funcName($funcSettings, $address); // every function has to return the modified address
                } catch(Exception $e) {
                    $errors[$funcName] = $e;
                }
            }

How can I check if it's callable? 如何检查它是否可调用? Why doesn't this work? 为什么不起作用?

可能这也可以解决问题:

 if(method_exists($this,$funcName)){ ... }

You have to use method_exists here to check if the method really exists in the class. 您必须在此处使用method_exists来检查该方法是否确实存在于类中。

foreach ($settings as $funcName => $funcSettings) {
    if (method_exists($this, $funcName)) {
        $this->$funcName($funcSettings, $address);
    }
}

The reason why is_callable will not work in your scenario is because Laravel controllers has a __call magic method which will handle undefined methods, so running is_callable on any non existing methods would return true. is_callable在您的情况下不起作用的原因是因为Laravel控制器具有__call magic方法,该方法将处理未定义的方法,因此在任何不存在的方法上运行is_callable都将返回true。

Take the following class as an example: 以下面的类为例:

class A
{
    public function __construct()
    {
        var_dump(is_callable([$this, 'testFunc']));
    }
}

The output of new A would be false . new A的输出为false However, if you add the following into the class: 但是,如果将以下内容添加到该类中:

public function __call($name, $arguments)
{
    //
}

Now the output of the var_dump would return true . 现在, var_dump的输出将返回true

You can read more about the __call scenario I've mentioned right here: https://www.php.net/manual/en/function.is-callable.php#118623 您可以在此处阅读有关我刚才提到的__call方案的更多信息: https : //www.php.net/manual/zh/function.is-callable.php#118623

For more information about __call : https://www.php.net/manual/en/language.oop5.overloading.php#object.call 有关__call更多信息: https : //www.php.net/manual/zh/language.oop5.overloading.php#object.call

You can use 您可以使用

if (is_callable([$this, $funcName])) { ...

instead. 代替。

The way you have it written with is_callable($this->$funcName) , it's going to look for a property called $funcName on $this , (which probably doesn't exist) and check if that's callable. is_callable($this->$funcName)编写的方式是,在$this上查找一个名为$funcName的属性(可能不存在),并检查是否可调用。 If you use that array syntax it will evaluate the named method instead. 如果使用该数组语法,它将代之以命名方法。


It may be simpler in this case to use 在这种情况下使用可能会更简单

if (method_exists($this, $funcName)) {

since you're using it in another method of the same object, if the method exists it should be callable. 因为您正在同一对象的另一个方法中使用它,所以如果该方法存在,则该方法应该是可调用的。

You need to differentiate between class properties and methods. 您需要区分类属性和方法。 For example in this class: 例如在此类中:

class A {
    private $foo = null;

    public function getFoo() {
        return $this->foo;
    }
}
  • the private $foo is property and can be checked by property_exists() private $foo是属性,可以由property_exists()检查
  • the public function getFoo() is method and can be checked by method_exists() public function getFoo()是method,可以通过method_exists()进行检查

https://www.php.net/manual/en/function.property-exists.php https://www.php.net/manual/zh/function.property-exists.php
https://www.php.net/manual/en/function.method-exists.php https://www.php.net/manual/zh/function.method-exists.php

I think that $this->$funcName works only for properties. 我认为$this->$funcName仅适用于属性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM