【问题标题】:PHP override weak function return type coercionPHP覆盖弱函数返回类型强制
【发布时间】:2018-06-15 14:04:06
【问题描述】:

根据 PHP 文档中的 Strict Typing 找到 here

默认情况下,如果可能,PHP 会将错误类型的值强制转换为预期的标量类型。例如,为期望字符串的参数提供整数的函数将获得字符串类型的变量。

我很好奇是否有办法覆盖此功能以自定义强制完成的方式。

例如

function getResponse() : \Namespace\Response {
    return []; // Ideally, this would be coerced into a Response object.
}

. . .

namespace Namespace;

class Response {
    public $data;         

    public function __construct(array $arr)
    {
        $this->data = $arr;
    }

    public static function __coerce($value)
    {
        if (! is_array($value)) {
            throw new \TypeError('Wrong type during coercion.');
        }

        return new self($value);
    }
}

【问题讨论】:

  • 我不太了解“自定义”强制转换的概念。严格输入是onoff。而且,如果您曾经超过文档中的第一句话,您就会看到,严格输入将在每个文件的基础上打开:declare(strict_types=1);
  • 顺便说一句。如果你想要严格的返回类型,你应该使用 Java。
  • @AlexKarshin 我正在尝试覆盖强制的功能。我知道可以打开或关闭严格输入。我希望能够键入提示函数的返回类型,并返回不是该类型提示类型的类型,并且这样做时,我可以覆盖类型提示类型中的函数来处理外部类型改成那个类型。
  • 唯一的解决方案是下载源代码并按照您想要的方式对其进行编辑,然后编译并使用。 AFAIK,没有其他办法。
  • 我的建议是在你的代码中完全不要依赖强制 - 最后 PHP 有严格的类型!拥抱它=)

标签: php php-7 type-coercion


【解决方案1】:

这是不可能的,因为这是编译时语言级别的评估。

你唯一能做的就是覆盖父返回类型:

public function getResponse(): []  // though parent has "Reponse" type
{
    return [];
}

【讨论】:

    【解决方案2】:

    我已经在 PHP 中编写了自己的实现来执行此操作,因为不存在。这就是它的工作原理。

    这是两个基本函数。


    1. multiReturnFunction 函数。(用于调用全局函数和匿名函数)
    /**
     * Call a global function and use type coercion
     * for non-registered return types. 
     *
     * @param  closure $closure    The function to execute. 
     * @param  string  $returnType The registered return type.
     * @param  array   $params     The parameters to pass to the function. 
     * 
     * @return mixed The result of the function to execute.
     */
    function multiReturnFunction($closure, $returnType, ...$params)
    {
        $val = $closure(...$params);
    
        if (gettype($val) === 'object') {
            if (get_class($val) != $returnType) {
                if (method_exists($returnType, '__coerce')) {
                    $val = $returnType::__coerce($val);
                } else {
                    throw new \Exception(
                        'Returned value does not match the return type defined, '.
                        'and no __coerce function is visible.'
                    );
                }
            }
        } else if (gettype($val) != $returnType) {
            if (method_exists($returnType, '__coerce')) {
                $val = $returnType::__coerce($val);
            } else {
                throw new \Exception(
                    'Returned value does not match the return type defined, '.
                    'and no __coerce function is visible.'
                );
            }
        }
    
        return $val;
    }
    

    multiReturnFunction 函数将调用一个闭包并使用返回类型类的__coerce 函数来强制返回类型,如果结果返回类型不匹配。

    multiReturnFunction 函数示例

    • 定义我们将使用的类,并确保给它一个__coerce 函数。

      注意:__coerce 函数为我们将尝试强制转换为此类类型的对象采用单个变量。该函数必须声明为静态的。

      class MyClass
      {
          private $data;
      
          public function __construct(array $value)
          {
              $this->data = $value;
          }
      
          public static function __coerce($value)
          {
              if (! is_array($value)) {
                  throw new \Exception(
                      'Returned value does not match the return type defined.'
                  );
              }
      
              return new self($value);
          }
      }
      
    • 接下来,您需要使用您的类和一个匿名函数调用 multiReturnFunction 函数。

      $resultingMyClass = multiReturnFunction (
          // Multi return type function.
          function($name, $age) {
              // Here you can return either a MyClass instance, or an array.
              // All other types will throw an exception.
      
              return [$name, $age];
          },
      
          // Return Type, any other type will be coerced through this class.
          MyClass::class,
      
          // Function parameters.
          'Nathan', 23
      );
      

    1. multiReturnMethod 函数。(用于调用类方法)

      /*
       * Call a class method and use type coercion
       * for non-registered return types. 
       *
       * @param  object  $obj        The object to call the method on.
       * @param  string  $method     The method to call on the object.
       * @param  string  $returnType The registered return type.
       * @param  array   $params     The parameters to pass to the method. 
       * 
       * @return mixed The result of the method to execute.
       */
      function multiReturnMethod($obj, $method, $returnType, ...$params)
      {
          $val = $obj->{$method}(...$params);
      
          if (gettype($val) === 'object') {
              if (get_class($val) != $returnType) {
                  if (method_exists($returnType, '__coerce')) {
                      $val = $returnType::__coerce($val);
                  } else {
                      throw new \Exception(
                          'Returned value does not match the return type defined, '.
                          'and no __coerce function is visible.'
                      );
                  }
              }
          } else if (gettype($val) != $returnType) {
              if (method_exists($returnType, '__coerce')) {
                  $val = $returnType::__coerce($val);
              } else {
                  throw new \Exception(
                      'Returned value does not match the return type defined, '.
                      'and no __coerce function is visible.'
                  );
              }
          }
      
          return $val;
      }
      

    multiReturnMethod函数会调用一个类方法,如果结果返回类型不匹配,会使用返回类型类的__cooerce函数强制返回类型。

    multiReturnMethod 函数示例

    注意:我们将使用之前创建的MyClass 类作为返回类型。

    • 定义一个我们可以用来调用类方法的类。

      class MRFClass {
          function callMe($name)
          {
              return [$name, 1, 2, 3];
          }
      }
      
    • 使用您的类和匿名函数调用multiReturnMethod 函数。

      $resultingMyClass = multiReturnMethod (
          // The object that we will be calling the
          // class method on.
          new MRFClass(),
      
          // The class method to call, by name.
          'callMe',
      
          // The return type to coerce to.
          MyClass::class,
      
          // The function parameters.
          'Nathan'
      );
      

    这两种方法都可用于强制执行严格的返回类型函数,这些函数接受多个返回类型,这些返回类型可以在每个类的实现中强制为返回类型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-06
      • 1970-01-01
      • 2018-01-19
      • 1970-01-01
      相关资源
      最近更新 更多