PHP覆盖弱函数返回类型强制

时间:2018-01-05 18:07:03

标签: php php-7 type-coercion

根据有关Strict Typing的PHP文档here

  

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

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

例如

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);
    }
}

2 个答案:

答案 0 :(得分:0)

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

您唯一能做的就是覆盖父回复类型:

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

答案 1 :(得分:0)

我已经编写了自己的实现来在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;
    }
    
  2. 如果结果返回类型不匹配,multiReturnFunction函数将调用一个闭包并使用返回类型类的__coerce函数来强制返回类型。

    multiReturnFunction功能

    的示例
    • 定义我们将要使用的类,并确保为其提供__coerce函数。

        

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

      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;
      }
      
    2. 如果结果返回类型不匹配,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'
        );
        

      这两个方法都可以用来强制严格的返回类型函数,它接受多个返回类型,可以强制转换为每类实现的返回类型。