为用户定义的对象types转换

就像我们用__ToString做的那样,是否有一种方法来定义一个铸造的方法?

$obj = (MyClass) $another_class_obj; 

没有必要在php中input。


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

在诸如Java这样的语言中,有两种可能带有types的东西。 编译器有一个关于types的概念,而运行时对types有另一个想法。 编译器types绑定到variables,而运行时引擎跟踪值的types(分配给variables)。 variablestypes在编译时已知,而值types只在运行时才知道。

如果一段input代码违反了编译器types系统,编译器将会禁止编译。 换句话说,编译违反静态types系统的代码是不可能的。 这捕捉到了某种types的错误。 例如,采取以下(简化)Java代码:

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

如果我们现在这样做了:

 Alpha a = new Beta(); 

我们会没事的,因为BetaAlpha一个子类,因此Alphatypes的variablesa是有效的值。 但是,如果我们继续做:

 a.sayHello(); 

编译器会给出一个错误,因为方法sayHello不是Alpha的有效方法 – 不pipe我们知道a实际上是一个Beta

inputtypes转换:

 ((Beta) a).sayHello(); 

在这里,我们告诉编译器,variablesa应该在这种情况下被视为Beta 。 这被称为types转换。 这个漏洞是非常有用的,因为它允许在语言中的多态性,但显然这也是各种types系统违规的后门。 为了保持一些types的安全,因此有一些限制; 您只能投射到相关的types。 例如。 向上或向下的层次结构。 换句话说,你不能投给一个完全无关的class级Charlie

需要注意的是,所有这些都发生在编译器中 – 也就是说,在代码运行之前就发生了这种情况。 Java仍然可以运行时间types错误。 例如,如果你这样做:

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

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

同时,回到PHP农场。

以下是对PHP编译器有效 – 它会愉快地把它变成可执行的字节码,但是你会得到一个运行时错误:

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

这是因为PHPvariables没有types。 编译器不知道什么运行时types对variables有效,所以不会试图执行它。 不像Java那样显式地指定types。 有提示,是的,但这些只是运行时间合同。 以下依然有效:

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

即使PHP variables没有types, 仍然可以。 PHP的一个特别有趣的方面是可以改变一个值的types。 例如:

 // 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" 

这种function有时与types铸造混淆,但这是一个误用。 该types仍然是该值的属性,types更改在运行时发生 – 而不是在编译时。

在PHP中改变types的能力也相当有限。 只能在简单types之间改变types – 不是对象。 因此,不可能将types从一个类改为另一个类。 您可以创build一个新的对象并复制状态,但更改types是不可能的。 在这方面PHP是一个局外人; 其他类似的语言将类视为比PHP更dynamic的概念。

PHP的另一个类似的function是,你可以将一个值克隆为一个新types,如下所示:

 // 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" 

在语法上,这看起来很像是一个types化语言是如何写成静态types的语言的。 因此它也经常与types转换混淆,尽pipe它仍然是一个运行时types转换。

总结:types转换是一种改变variablestypes( 不是值)的操作。 由于variables没有在PHP中input,所以这不仅是不可能的,而且是一个无意义的事情。

这里有一个函数来改变一个对象的类:

 /** * Change the class of an object * * @param object $obj * @param string $class_type * @author toma at smartsemantics dot com * @see http://www.php.net/manual/en/language.types.type-juggling.php#50791 */ function changeClass(&$obj,$new_class) { if(class_exists($class_type,true)) { $obj = unserialize(preg_replace("/^O:[0-9]+:\"[^\"]+\":/i", "O:".strlen($class_type).":\"".$new_class."\":", serialize($obj))); } } 

如果不清楚,这不是我的function,它是从一个职位“toma at smartsemantics点com” http://www.php.net/manual/en/language.types.type-juggling.php #50791

尽pipe不需要在PHP中input强制types,但是您可能会遇到您想要将父对象转换为子对象的情况。

简单

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

这不是types转换,而是它所需要的。

我重写了Josh发布的函数(由于未定义的$ new_classvariables,这会导致错误)。 这是我得到的:

 function changeClass(&$obj, $newClass) { $obj = unserialize(preg_replace // change object into type $new_class ( "/^O:[0-9]+:\"[^\"]+\":/i", "O:".strlen($newClass).":\"".$newClass."\":", serialize($obj) )); } function classCast_callMethod(&$obj, $newClass, $methodName, $methodArgs=array()) { $oldClass = get_class($obj); changeClass($obj, $newClass); // get result of method call $result = call_user_func_array(array($obj, $methodName), $methodArgs); changeClass(&$obj, $oldClass); // change back return $result; } 

它就像你所期望的一个class级工作。 你可以build立类似的访问类的成员 – 但我不认为我会永远需要,所以我会把它留给别人。

嘘所有的混蛋说,“PHP不投”或“你不需要在PHP中投”。 Bullhockey。 Casting是面向对象生活的重要组成部分,我希望能find比丑陋的序列化入侵更好的方法。

所以谢谢乔希!

我认为你需要input,以便创build一个更好的IDE。 但是php语言本身并不需要types转换,但它支持运行时types对variables值的更改。 看看自动装箱和拆箱。 这就是php固有的function。 所以对不起,已经是IDE了。

如果你想要铸造types暗示,那么这个工作就行了。

 if( is_object($dum_class_u_want) && $dum_class_u_want instance of ClassYouWant ) { //type hints working now $dum_class_u_want ->is_smart_now(); } 

是的。

我不相信在PHP中有一个重载操作符来处理,但是:

 <?php class MyClass { protected $_number; static public function castFrom($obj) { $new = new self(); if (is_int($obj)) { $new->_number = $obj; } else if ($obj instanceOf MyNumberClass){ /// some other type of casting } return $new; } } $test = MyClass::castFrom(123123); var_dump($test); 

是一个办法来处理它。