将PHP转换成我的类

52
为什么这是不可能的:
$user = (User) $u[0];

但这是可能的

$bool = (boolean) $res['success'];

我使用 PHP 7.0。


将对象强制转换为Object类型是不安全的。您为什么要这样做呢?不确定是否相关,您可以使用instanceof来检查对象的类。 - Raptor
$u[0] 是什么? - A.L
3
据我所知,你只能强制转换基本数据类型。请参阅[类型强制转换]http://php.net/manual/de/language.types.type-juggling.php。 - Jarlik Stepsto
是的,PHP不像C#那样支持隐式转换:https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/using-conversion-operators - Joel Harkes
7个回答

55

您可以使用PHPDoc

/** @var User $user */
$user = $u[0];

3
在PHP中,将变量转换为类只有在用于IDE自动完成/建议时才有作用。因此,PHPDoc是正确的方法。您甚至可以通过只写/** @var User */而不写变量名来简化它。 - Dawid Ohia
2
假设您只是想添加类型提示以进行静态分析。运行时转换/断言对于防止错误更有用,并且如果您使用的静态分析工具甚至有一半的能力,那么运行时转换/断言将固有地带来“编译时”信息。 - Andrew Koster

44

据我所知,在PHP中,您只能将某些类型强制转换:

(int), (integer) - cast to integer
(bool), (boolean) - cast to boolean
(float), (double), (real) - cast to float  (real deprecated in PHP 8.0)
(string) - cast to string
(binary) - cast to binary string (PHP 6)
(array) - cast to array
(object) - cast to object
(unset) - cast to NULL (PHP 5) (depracted in PHP 7.2) (removed in 8.0)

(请参见类型转换)

你也可以使用instanceof来检查特定类型:

if($yourvar instanceof YourClass) {
    //DO something
} else {
    throw new Exception('Var is not of type YourClass');
}

编辑

如Szabolcs Páll在他的回答中提到的那样,也可以声明一个返回类型参数类型,但在这种情况下,如果类型不匹配,则会抛出一个异常(TypeError)。

function test(): string
{
    return 'test';
}

function test(string $test){
    return "test" . $test;
}
自 PHP 7.2 版本起,可以在类型前面添加 ? 来使其可为 null 值:
function test(): ?string
{
    return null;
}

17
如果您只想确保一个变量是 YourClass 的实例,并让异常处理交给类型系统,您可以使用以下函数:
function implicitFakeCast($myClass): YourClass
{
    return $myClass;
}
注意:这实际上不会进行任何强制转换,而是在出现类别不匹配的情况下抛出异常,并让智能提示将其视为目标类的实例。

3
异常应该用于处理在特殊情况下发生的异常情况,而不是作为程序逻辑或执行测试的常规方法。 - lee
5
非常同意,实际上在函数/方法的返回值中出现意料之外的类,可能会像试图强制转换不可转换的类型一样异常。 - Szabolcs Páll
3
存在类型错误的代码肯定应该被视为“异常”的。 - Andrew Koster
1
我也想到了这个解决方案。$class = Derived::class; $instance = self::castAsBaseAbstract(new $class()); ... private static function castAsBaseAbstract($object): BaseAbstract{ return $object; }。虽然这是一个很好的解决方案,但像@adir-kandel建议的那样使用phpDoc更容易。这里异常的概念并不重要。这完全是为了获得智能提示的好处。我的用例中,类类型存储在数组中,并在循环中创建实例。所有实例都派生自同一基类。 - TonyG

11

对于那些想要将对象转换为类类型的人,我发现@borzilleri的gist使用serialize和unserialize可以实现这一点:https://gist.github.com/borzilleri/960035

TL;DR:

// make sure to include the namespace when casting
$className = "Some\\NameSpace\\SomeClassName";
$classNameLength = strlen( $className );
$castedItem = unserialize(
    preg_replace(
        '/^O:\d+:"[^"]++"/',
        "O:$classNameLength:\"$className\"",
        serialize( $item )
    )
)

4
什么肮脏的窍门!喜欢这个 :) - Daishi

7

在 PHP 8 中,这非常简单:

 $item = (fn($item):YourClass=>$item)($item);

2
如果$itemYourClass的实例,则此代码不执行任何操作,否则它将抛出类型错误。 - miken32
3
是的,这就是重点!但是,它确保您的实例是 YourClass,并且副作用是,IDE(phpstorm)将知道它...(而不需要任何丑陋的注释...)。 这几乎是由 @szabolcs-páll 提供的相同解决方案,但使用了 php8 的箭头函数,作为内联解决方案... - Gergely Laborci
喜欢这个解决方案,谢谢!只是提醒一下,这在 PHP 7.4 中可行 https://www.php.net/manual/en/functions.arrow.php - infojunkie
非常直观! - Pepijn Olivier
为了明确起见:如果$item的类型是object,那么这将导致TypeError。它不会转换或改变对象的类型。 - undefined

3

对象和基本类型是不同的。由于被称为基本类型,它们非常简单,可能只有1字节、2字节或4字节,最多8字节。

当我们谈论对象时,这个对象可以与其他对象具有不同的属性。PHP的问题就是“这个对象真的来自我的类吗?”“如何将这个对象转换为我的类?”因此,您不能立即使用解析对象。

$myObject = (ClassName) $variable

那么如何进行投射呢?不太清楚,但通常的方法是这样的:

  1. 为类创建构造函数
  2. 在类中,编写一个专门接受某些参数(可能是数组)的方法

下面是示例:

public class MyAwesomeClass{


     function __construct($thisIsArray){
         $this->attributeA = $thisIsArray["A"];
         $this->attributeB = $thisIsArray["B"];
         ......
     }

     static function fromArray($thisIsArray){
         return MyAwesomeClass($thisIsArray);
     }

}

$obj = MyAwesomeClass::fromArray($attributes);

希望PHP能够以某种方式提供“.”语法。但在此之前,您可以使用$obj = MyAwesomeClass::fromArray($attributes); - MohannadNaj

1
除了为什么这不可能的答案之外,我建议您编写一个构建函数,根据您的输入创建一个对象。因此它会看起来像这样:
$user = User::buildFromSomeArrayInput($u[0]);

然后创建一个构建器来创建一个新的对象,分配正确的属性等。当然,你可以在现场完成所有这些工作,但是拥有一个构建器函数可以确保你不会在多个位置上进行此操作,并且你可以设置私有属性,因为它是一个类成员函数。它比神奇地工作要多一点工作,但并不是那么多。 你可能唯一遇到的问题是当你有一个不公开所有内部细节的不同对象时。但这是有原因的,因为内部细节可能会改变,你不想依赖它们。 有一些黑客技巧建议使用序列化来完成此操作。我建议远离它们,因为它们很hackish,而且就我而言,不太清晰。

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