为用户定义的对象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();
我们会没事的,因为Beta
是Alpha
一个子类,因此Alpha
types的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,因为从Beta
到Charlie
是不兼容的。
同时,回到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);
是一个办法来处理它。