用户定义对象的类型强制转换

2022-08-30 09:44:03

就像我们对__ToString所做的那样,有没有办法定义铸造方法?

$obj = (MyClass) $another_class_obj;

答案 1

没有必要在php中键入cast。


编辑:由于这个话题似乎引起了一些混乱,我想我会详细阐述一下。

在Java等语言中,有两个东西可能带有类型。编译器有一个关于类型的概念,而运行时有另一个关于类型的概念。编译器类型与变量相关联,而运行时引擎跟踪值的类型(分配给变量)。变量类型在编译时是已知的,而值类型仅在运行时是已知的。

如果一段输入代码违反了编译器类型系统,编译器将 barf 并暂停编译。换句话说,不可能编译一段违反静态类型系统的代码。这会捕获特定类别的错误。例如,采用以下(简化的)Java 代码:

class Alpha {}

class Beta extends Alpha {
  public void sayHello() {
    System.out.println("Hello");
  }
}

如果我们现在这样做:

Alpha a = new Beta();

我们就可以了,因为它是 的子类,因此是 类型变量的有效值。但是,如果我们继续这样做:BetaAlphaaAlpha

a.sayHello();

编译器会给出一个错误,因为该方法不是 - 无论我们知道它实际上是一个.sayHelloAlphaaBeta

输入类型转换:

((Beta) a).sayHello();

在这里,我们告诉编译器,在这种情况下,变量应该被视为 .这称为类型转换。这个漏洞非常有用,因为它允许在语言中多态性,但显然它也是各种违反类型系统的后门。为了保持某种类型安全,因此有一些限制;只能强制转换为相关的类型。例如。向上或向下层次结构。换句话说,您将无法强制转换为完全不相关的类 。aBetaCharlie

重要的是要注意,所有这些都发生在编译器中 - 也就是说,它发生在代码运行之前。Java 仍然可以进入运行时类型错误。例如,如果您执行以下操作:

class Alpha {}

class Beta extends Alpha {
  public void sayHello() {
    System.out.println("Hello");
  }
}

class Charlie extends Alpha {}

Alpha a = new Charlie();
((Beta) a).sayHello();

上面的代码对编译器有效,但在运行时,你会得到一个异常,因为从 到 的强制转换是不兼容的。BetaCharlie

与此同时,回到PHP农场。

以下内容对 PHP 编译器有效 - 它会很乐意将其转换为可执行字节代码,但您将收到运行时错误:

class Alpha {}

class Beta extends Alpha {
  function sayHello() {
    print "Hello";
  }
}
$a = new Alpha();
$a->sayHello();

这是因为 PHP 变量没有类型。编译器不知道哪些运行时类型对变量有效,因此它不会尝试强制执行它。您也不会像在 Java 中那样显式指定类型。是的,有类型提示,但这些只是运行时协定。以下内容仍然有效:

// reuse the classes from above
function tellToSayHello(Alpha $a) {
  $a->sayHello();
}
tellToSayHello(new Beta());

即使 PHP 变量没有类型,这些仍然有类型。PHP的一个特别有趣的方面是可以更改值的类型。例如:

// The variable $foo holds a value with the type of string
$foo = "42";
echo gettype($foo); // Yields "string"
// Here we change the type from string -> integer
settype($foo, "integer");
echo gettype($foo); // Yields "integer"

此功能有时与类型转换混淆,但这是用词不当。类型仍然是值的属性,类型更改发生在运行时 - 而不是在编译时。

在PHP中,更改类型的能力也非常有限。只能在简单类型之间更改类型,而不能更改对象。因此,无法将类型从一个类更改为另一个类。您可以创建新对象并复制状态,但无法更改类型。PHP在这方面有点局外人;其他类似的语言将类视为比PHP更动态的概念。

PHP的另一个类似功能是,您可以将值克隆为新类型,如下所示:

// The variable $foo holds a value with the type of string
$foo = "42";
echo gettype($foo); // Yields "string"
// Here we change the type from string -> integer
$bar = (integer) $foo;
echo gettype($bar); // Yields "integer"

从语法上讲,这看起来很像静态类型语言中编写类型转换的方式。因此,它也经常与类型转换混淆,即使它仍然是运行时类型转换。

总结一下:类型强制转换是更改变量类型(而不是值)的操作。由于变量在PHP中没有类型,因此不仅不可能做到,而且首先要问这是一件荒谬的事情。


答案 2

虽然不需要在 PHP 中键入强制转换,但您可能会遇到想要将父对象转换为子对象的情况。

简单

//Example of a sub class
class YourObject extends MyObject {
    public function __construct(MyObject $object) {
        foreach($object as $property => $value) {
            $this->$property = $value;
        }
    }
}


$my_object = new MyObject();
$your_object = new YourObject($my_object);

因此,您所要做的就是将父对象向下传递给子对象的构造函数,并让构造函数复制属性。您甚至可以根据需要过滤/更改它们。

高深

//Class to return standard objects
class Factory {
    public static function getObject() {
        $object = new MyObject();
        return $object;
    }
}

//Class to return different object depending on the type property
class SubFactory extends Factory {
    public static function getObject() {
        $object = parent::getObject();
        switch($object->type) {
        case 'yours':
            $object = new YourObject($object);
            break;
        case 'ours':
            $object = new OurObject($object);
            break;
        }
        return $object;
    }
}

//Example of a sub class
class YourObject extends MyObject {
    public function __construct(MyObject $object) {
        foreach($object as $property => $value) {
            $this->$property = $value;
        }
    }
}

它不是类型转换,但它可以满足您的需要。


推荐