PHP类型提示如何对原始值进行处理?

79

我想知道是否可以使用类型提示来指定方法期望的基本数据类型?

就像这样:

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

或者:

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

你可以用同样的方式:

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

在PHP中是否可能实现这个功能?


2
在PHP中,类型提示(Type Hinting)是指在函数或方法的参数列表中指定参数类型。该特性旨在提高代码的可读性和可维护性,并减少由于类型错误引起的潜在问题。要了解更多关于Type Hinting的信息,请访问http://php.net/manual/en/language.oop5.typehinting.php。 - Pramendra Gupta
11
仅使用PHP 7。 - zloctb
如果您没有使用 PHP 7.x,您可以使用 NSPL 中的 args 模块 - Ihor Burlachenko
8个回答

92
在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)不能与类型提示一起使用。资源和特性也不允许。参考:http://php.net/manual/en/language.oop5.typehinting.php

1
好的。谢谢。你认为他们将在未来任何时候提供它吗?还是像他们所说的那样,它不符合PHP的哲学? - Felipe
1
@Felipe 这是其中一种情况,PHP 团队并不在意 / 不想改变任何东西,即使现有的行为已经出了问题或者不理想。他们的问题跟踪器中充满了这些内容;请查看我的答案,了解与类型提示相关的具体问题。 - Rafe Kettler
我认为PHP在不久的将来没有使用类型的愿望。 你为什么关心类型? - afuzzyllama
@Rafe Kettler 怎么了?根据w3c的说法,它不是这样的。我不知道有什么方法可以将变量绑定到某种类型。 - afuzzyllama
21
@afuzzyllama,w3schools并不是W3C。W3C时常向他们提出警告,要求他们停止误导人们认为他们是W3C。PHP的开发者声称它是强类型语言(这实际上是成为强类型语言的唯一必要条件),但实际上并不是。当我评论它是强类型语言时,我不知道我在想什么。 - Rafe Kettler
2015年更新和即将到来的PHP 7:http://www.phpclasses.org/blog/post/269-PHP-7-Scalar-Type-Hinting-Finally-Approved.html - timhc22

26

不行。你不能为原始类型进行类型提示,因为 PHP 会自动转换原始类型。请参见 http://bugs.php.net/bug.php?id=29508。这种情况永远不会改变,除非 PHP 团队突然改变心意(这是可怀疑的,他们非常固执)。


12
2015年更新和即将到来的PHP7:http://www.phpclasses.org/blog/post/269-PHP-7-Scalar-Type-Hinting-Finally-Approved.html本文介绍了PHP 7的新功能——标量类型提示,并解释了其优势。该功能能够提高代码的可读性、可维护性和安全性,因此PHP开发人员应该关注这个重要的变化。 - timhc22

19

现在,这是可能的了。 经过长时间的讨论,一个提案被批准,允许对标量函数参数和返回值进行类型提示。有关详细信息,请查看最高票数的投票结果。

标量类型提示包括声明函数参数和返回值的类型,可以是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

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

Like : declare(strict_types=1);

在运行时,当PHP引擎尝试返回一个值时,如果它与声明的类型不匹配,它将抛出致命错误,如下所示:

Fatal error: Argument 1 passed to increment() must be of the type integer, string given

通过这种新的声明特性,您可以编写更加健壮的应用程序,通过检测将错误类型的值传递给函数而引起的早期编程错误。

类型的自动转换也可能发生。例如,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视为面向对象编程语言参考的开发人员而言,这是PHP的巨大进步。


这不是Hack而不是PHP吗? - Felipe
这是真的吗?我们可以期待在哪个版本中推出这些功能? - robbmj
请注意...除非有一个名为"type numeric"的类或接口,否则它不存在。 - DigiLive

6

大家都已经说了,你不能对原始类型进行类型提示,因为PHP不支持。这背后的原因不仅与自动转换有关,还与社区反应有关。

据我所知,2010年5月,支持标量类型提示被添加到了PHP trunk中。但由于社区的反应,这个功能没有出现在5.4版本中。

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

我个人的看法:标量类型提示应该尽快添加到PHP中,它是我们所有人都需要的功能,我非常尊重PHP是弱类型语言,但对于高端开发和生产,特别是在OO上下文中,标量类型提示是必不可少的。我们可以在PHP中拥有两种选择,就像过程式和面向对象一样。


3

是的,这是可能的。

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 6.0中类型提示的讨论,请关注PHP Internals 论坛。

<?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.

?>

你能理解这个画面了吗?

1

根据PHP文档,原始类型不支持类型提示。

但是,它支持类和接口。

编辑:我忘了提到它也支持数组。


嗯...我不认为接口支持这个...或者我错了吗? - Felipe
1
我是为了接口而这么做的。那么我非常确定你是错的 :-) - Luc M
嗯...我之前也问过同样的问题。我得到的普遍印象是它不起作用...看这里http://stackoverflow.com/questions/5346393/what-other-languages-allow-programmers-to-use-interfaces-as-function-parameters - Felipe
我需要对我的代码进行一些测试... 我有像 MyMethod( iMyInterface $some_interface ) 这样的方法... 如果我传递的东西没有实现 iMyInterface 接口,它就不会“编译”。但是我没有尝试传递一个只实现了要实现的方法名称的类而没有实现接口。 - Luc M

0
以下是强制将传入参数转换为布尔值的简短语法。如果$state为真,则将$this->is_active设置为真。对于所有其他类型的值,它都被设置为假。
function set_active ( $state ) {
    $this->is_active = true === $state;
}

-3
我猜你在PHP中不需要类型提示,因为你可以使用诸如is_bool()、is_string()等类型检查函数来检查你要放入参数的内容,然后再将其作为参数传递。虽然它们用于检查数组和对象类型的方法会更加简洁。

5
зұ»еһӢжҸҗзӨәиғҪеӨҹйҒҝе…ҚеңЁжҜҸдёӘеҮҪж•°зҡ„жҜҸдёӘеҸӮж•°дёӯйғҪдҪҝз”Ёif(!is_bool($bool)) throw new InvalidTypeException('Arg $bool must be a boolean');иҝҷз§ҚеҲӨж–ӯиҜӯеҸҘгҖӮеҪ“жҲ‘и®ҫи®Ўй«ҳиҙЁйҮҸзҡ„APIж—¶пјҢжҲ‘жҖ»жҳҜжЈҖжҹҘеҸӮж•°зұ»еһӢгҖӮиҖҢзұ»еһӢжҸҗзӨәдјҡиҠӮзңҒеҫҲеӨҡifиҜӯеҸҘвҖҰвҖҰжҲ‘дёҚи®Өдёәдҝқз•ҷжүҖжңүиҝҷдәӣifиҜӯеҸҘдјҡжӣҙеҠ з®ҖжҙҒвҖҰвҖҰ - AlexMorley-Finch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接