【问题标题】:PHP type-hinting to primitive values?PHP类型提示原始值?
【发布时间】:2011-08-09 03:24:21
【问题描述】:

我想知道是否可以对一种方法进行类型提示以期望原始类型?

类似这样的:

public function someMethod(string $str)
                         //^^^^^^

或者:

private function anotherMethod(int $num)
                             //^^^

和你一样:

private function otherMethod(Person $rambo)
                           //^^^^^^

在 php 中可以吗?

【问题讨论】:

标签: php primitive-types type-hinting


【解决方案1】:

在 PHP 7 中,他们添加了以下内容:

类型声明允许函数在调用时要求参数为特定类型。如果给定值的类型不正确,则会产生错误:在 PHP 5 中,这将是一个可恢复的致命错误,而 PHP 7 将抛出 TypeError 异常。

参考: http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration


当被问及这个答案时,PHP 5 是最新的,并说如下:

PHP 5 引入了类型提示。函数现在能够将参数强制为对象(通过在函数原型中指定类的名称)、接口、数组(自 PHP 5.1 起)或可调用(自 PHP 5.4 起)。但是,如果将 NULL 用作默认参数值,则允许将其作为任何后续调用的参数。

如果将类或接口指定为类型提示,则也允许其所有子级或实现。

类型提示不能与 int 或 string 等标量类型一起使用。资源和 Traits 也是不允许的。

参考:http://php.net/manual/en/language.oop5.typehinting.php

【讨论】:

  • 好的。谢谢。你认为他们会在未来的任何时候提供它吗?还是他们所说的“与 php 哲学兼容”?
  • @Felipe 这是 PHP 团队不关心/根本不想改变的情况之一,即使现有行为被破坏或不受欢迎。他们的问题跟踪器充满了这些东西;有关与类型提示相关的具体问题,请参阅我的答案。
  • 我不认为 PHP 有任何希望很快开始使用类型。你为什么关心类型?
  • @Rafe Kettler 怎么样?根据w3c,它不是。无论如何我都不知道将变量绑定到某种类型。
  • @afuzzyllama w3schools 不是 w3c。 w3c 一直在困扰他们,以免误导人们认为他们就是他们。 PHP 开发人员声称它是强类型的(这实际上是强类型的唯一必要条件),但事实并非如此。当我评论它是强类型时,我不知道我在想什么。
【解决方案2】:

不。您不能为基元键入提示,因为 PHP 具有对基元的自动转换。见http://bugs.php.net/bug.php?id=29508。这永远不会改变,除非 PHP 团队突然改变主意(这是值得怀疑的,他们非常固执)。

【讨论】:

【解决方案3】:

基本类型不支持Accordind to PHP documentation 类型提示。

但它支持类和接口。

编辑:我忘了提到数组也支持这一点。

【讨论】:

  • 嗯..我认为接口不支持它......还是我错了?
  • 我这样做是为了界面。那我很确定你错了:-)
  • 嗯...我前段时间问过同样的问题..我的总体印象是它不起作用...看这里stackoverflow.com/questions/5346393/…
  • 我将不得不对我的代码进行一些测试......我有像 MyMethod(iMyInterface $some_interface) 这样的方法......如果我传递了一些不实现接口 iMyInterface 的东西,它不“编译”。但是我没有尝试在不实现接口的情况下传递具有要实现的方法名称的类。
【解决方案4】:

我猜你不需要 PHP 的类型提示,因为你已经获得了类型检查函数,例如 is_bool()、is_string() 等,所以你可以检查你之前尝试放入参数中的任何内容来反对这些函数实际上把它作为一个参数,虽然他们用来检查数组和对象类型的方法会更干净。

【讨论】:

  • 类型提示可以防止每个函数中的每个参数出现不必要的if(!is_bool($bool)) throw new InvalidTypeException('Arg $bool must be a boolean');。当我设计可靠的 API 时,我总是输入检查我的参数。并且类型提示会节省很多 if 语句...我不明白拥有所有这些 if 语句是如何cleaner...
【解决方案5】:

每个人都说过,你不能为原语做类型提示,因为 PHP 不支持它。这背后的原因不仅与自动转化有关,还与社区反应有关。

到目前为止,我记得在 2010 年 5 月,对标量类型提示的支持被添加到 PHP 主干中。但是由于社区的反应,这个功能没有进入 5.4 版本。

对此有一些争议。反对这一改变的人认为,这种支持将违背 PHP 的基本设计。 PHP被认为是一种弱类型语言。从本质上讲,这意味着 PHP 不需要您声明数据类型。变量仍然具有与之关联的数据类型,但您可以做一些激进的事情,例如将字符串添加到整数而不会导致错误。

恕我直言: 标量类型提示应该尽快添加到 PHP 中,这是我们都需要的功能,我非常尊重 PHP 是弱类型语言,但对于高端开发和生产,特别是在 OO在上下文中,标量类型提示是必须的。我们可以在 PHP 中同时使用这两种选择,就像过程和 OO 一样。

【讨论】:

    【解决方案6】:

    是的,现在有可能, 经过长时间的讨论,一个为标量函数参数和返回值实现类型提示的提案刚刚获得了迄今为止最高票数的批准,请查看详细信息:

    标量类型提示包括声明函数参数的类型和返回值,类型可以是 int、float、string 和 bool。这允许 PHP 运行时引擎检查传递给参数函数的值的类型并返回值是预期的类型,以便检测最终的编程错误。 过去的 PHP 版本已经允许对象、数组和可调用对象的类型提示。 当前实现引入了五个新的保留字:int、float、bool、string 和 numeric。这些以前没有保留,因为强制转换是词法分析器中的一种特殊情况。

    Example :
    function test(float $a) {
        var_dump($a); 
    }
    
    test(1); // float(1)
    test("1"); // float(1)
    test(1.0); // float(1)
    test("1a"); // E_RECOVERABLE_ERROR
    test("a"); // E_RECOVERABLE_ERROR
    test(""); // E_RECOVERABLE_ERROR
    test(1.5); // float(1.5)
    test(array()); // E_RECOVERABLE_ERROR
    test(new StdClass); // E_RECOVERABLE_ERROR
    

    您还可以选择在源文件中声明,您可以在其中允许 Scaler 类型提示。它必须是配置脚本的第一行,并且不能在同一文件的其他位置声明。

    Like : declare(strict_types=1);
    

    在运行时,当 PHP 引擎尝试返回一个值时,它会检查是否与声明的不匹配,它会抛出一个致命错误,例如, 致命错误:传递给 increment() 的参数 1 必须是整数类型,给定字符串

    借助这一新的声明特性,您可以通过检测由于将错误类型的值传递给函数而导致的早期编程错误,从而编写更健壮的应用程序。

    类型的自动更改也可能发生。比如int类型可以自动变成float类型参数,

    function test(float $x){
        var_dump($x);
    }
    test(10); // works fine
    

    声明返回类型

    我们可以声明返回类型,在函数声明的最后一个括号和第一个括号之间添加一个冒号,后跟预期的类型。

    对于不返回任何值的函数,不应在返回类型声明部分添加任何内容。

    function mustReturnInt(): int { ... }
    function mustReturnString(): string { ... }
    function mustReturnBool(): bool { ... }
    function mustReturnFloat(): float { ... }
    function doesNotReturnAnything() { ... }
    

    稍微复杂一点的例子

    declare(strict_types=1);  
    class StrictTypesTestingClass {  
    public function returnSameInt(int $value): int {   return $value;  }   
    public function returnSameFloat(float $value): float {   return $value;  }  
    public function returnSameString(string $value): string {   return $value;  }   
    public function returnSameBool(bool $value): bool {   return $value;  } }  
    $check = new StrictTypesTestingClass();  // calls that work  print $check->returnSameInt(10); 
    print $check->returnSameFloat(10.0); 
    print $check->returnSameString("test"); 
    print $check->returnSameBool(true) ? 'true' : 'false';  // calls that throw exceptions 
    print $check->returnSameInt("10"); 
    print $check->returnSameFloat("10.0"); 
    print $check->returnSameString(10);
    print $check->returnSameBool("true");
    

    弱类型检查和类型转换的行为:弱类型检查模式可以与语句 declare(strict_types=0); 一起使用或者没有严格的类型声明。有几点需要考虑: 对扩展或内置 PHP 函数的弱类型检查调用与以前的 PHP 版本具有相同的行为 新标量类型声明的弱类型检查规则与扩展或内置 PHP 函数的规则基本相同。 NULL 是一种特殊情况,以便与类、可调用对象和数组的当前类型声明保持一致。默认情况下不接受 NULL,除非它是一个参数并且明确地给出了一个默认值 NULL,例如:function sample(int $a = NULL);

    这种方法有很多优点。你得到类型安全。这意味着您终于可以静态分析代码了!您可以检测意外从一个函数中获取字符串并将其作为整数传递给另一个函数的错误。对于我这个每天使用 PHP 并将 Java 视为 OOP 语言参考的开发人员来说,这是 PHP 的一大进步.

    【讨论】:

    • 这不是Hack而不是PHP吗?
    • 这是真的吗?我们可以期待这些功能在哪个版本中首发?
    • 仅供参考...数字类型不存在,除非存在具有此名称的类或接口。
    【解决方案7】:

    这里是从传入参数中强制布尔值的简短语法。如果$state 为真,则$this->is_active 设置为真。对于所有其他类型的值,它设置为 false。

    function set_active ( $state ) {
        $this->is_active = true === $state;
    }
    

    【讨论】:

      【解决方案8】:

      是的,有可能。

      http://ru2.php.net/manual/ru/language.oop5.typehinting.php#83442

      警告:原始手册中有一个错字:resrouce 而不是 resource

      人们经常询问标量/基本类型提示。这是我在 MVC 框架中使用的一个类,它将通过使用自定义错误处理程序来启用类型提示。

      注意:您应该将此代码包含在包含头文件中的所有其他代码之上,如果您正在使用 set_error_handler() 函数,您应该知道这也会使用它。您可能需要链接您的 set_error_handlers()

      为什么?

      1. 因为人们厌倦了使用 is_* 函数来验证参数。
      2. 减少了防御性编码人员的冗余编码。
      3. 函数/方法是根据所需输入自行定义/记录的。

      还有.. 关注 PHP Internals 板上关于 PHP 6.0 中类型提示的讨论。

      <?php
      
      define('TYPEHINT_PCRE', '/^Argument (\d)+ passed to (?:(\w+)::)?(\w+)\(\) must be an instance of (\w+), (\w+) given/');
      
      class Typehint
      {
      
          private static $Typehints = array(
              'boolean'   => 'is_bool',
              'integer'   => 'is_int',
              'float'     => 'is_float',
              'string'    => 'is_string',
              'resource'  => 'is_resource'
          );
      
          private function __Constrct() {}
      
          public static function initializeHandler()
          {
      
              set_error_handler('Typehint::handleTypehint');
      
              return TRUE;
          }
      
          private static function getTypehintedArgument($ThBackTrace, $ThFunction, $ThArgIndex, &$ThArgValue)
          {
      
              foreach ($ThBackTrace as $ThTrace)
              {
      
                  // Match the function; Note we could do more defensive error checking.
                  if (isset($ThTrace['function']) && $ThTrace['function'] == $ThFunction)
                  {
      
                      $ThArgValue = $ThTrace['args'][$ThArgIndex - 1];
      
                      return TRUE;
                  }
              }
      
              return FALSE;
          }
      
          public static function handleTypehint($ErrLevel, $ErrMessage)
          {
      
              if ($ErrLevel == E_RECOVERABLE_ERROR)
              {
      
                  if (preg_match(TYPEHINT_PCRE, $ErrMessage, $ErrMatches))
                  {
      
                      list($ErrMatch, $ThArgIndex, $ThClass, $ThFunction, $ThHint, $ThType) = $ErrMatches;
      
                      if (isset(self::$Typehints[$ThHint]))
                      {
      
                          $ThBacktrace = debug_backtrace();
                          $ThArgValue  = NULL;
      
                          if (self::getTypehintedArgument($ThBacktrace, $ThFunction, $ThArgIndex, $ThArgValue))
                          {
      
                              if (call_user_func(self::$Typehints[$ThHint], $ThArgValue))
                              {
      
                                  return TRUE;
                              }
                          }
                      }
                  }
              }
      
              return FALSE;
          }
      }
      
      Typehint::initializeHandler();
      
      ?>
      
      An are some examples of the class in use:
      
      <?php
      
      function teststring(string $string) { echo $string; }
      function testinteger(integer $integer) { echo $integer; }
      function testfloat(float $float) { echo $float; }
      
      // This will work for class methods as well.
      
      ?>
      

      你明白了..

      【讨论】:

        猜你喜欢
        • 2017-03-05
        • 1970-01-01
        • 2013-05-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-06
        相关资源
        最近更新 更多