就像我们使用__ToString一样,有没有办法定义一个方法来进行投射?
$obj = (MyClass) $another_class_obj;
Run Code Online (Sandbox Code Playgroud)
tro*_*skn 100
没有必要在php中输入强制转换.
编辑: 由于这个话题似乎引起了一些混乱,我想我会详细说明一下.
在诸如Java之类的语言中,有两种东西可以携带类型.编译器有关于类型的概念,运行时对类型有另一种想法.编译器类型与变量相关联,而运行时引擎跟踪值的类型(分配给变量).变量类型在编译时是已知的,而值类型仅在运行时已知.
如果输入代码违反了编译器类型系统,编译器将禁止并停止编译.换句话说,编译违反静态类型系统的代码是不可能的.这会捕获某类错误.例如,采用以下(简化的)Java代码:
class Alpha {}
class Beta extends Alpha {
public void sayHello() {
System.out.println("Hello");
}
}
Run Code Online (Sandbox Code Playgroud)
如果我们现在这样做:
Alpha a = new Beta();
Run Code Online (Sandbox Code Playgroud)
我们会没事的,因为Beta它是类Alpha的变量a的有效值,因此是类的变量的有效值Alpha.但是,如果我们继续这样做:
a.sayHello();
Run Code Online (Sandbox Code Playgroud)
编译器会给出错误,因为该方法sayHello不是有效的方法Alpha- 无论我们知道它a实际上是一个Beta.
输入类型转换:
((Beta) a).sayHello();
Run Code Online (Sandbox Code Playgroud)
在这里,我们告诉编译器变量a应该 - 在这种情况下 - 被视为一个Beta.这被称为类型铸造.这个漏洞非常有用,因为它允许语言中的多态性,但显然它也是各种违反类型系统的后门.为了保持某种类型的安全性,因此存在一些限制; 您只能转换为相关的类型.例如.上下层次结构.换句话说,您将无法转换为完全不相关的类Charlie.
重要的是要注意所有这些都发生在编译器中 - 也就是说,它发生在代码甚至运行之前.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();
Run Code Online (Sandbox Code Playgroud)
上面的代码对编译器有效,但在运行时,你会得到一个异常,因为转换为Betato Charlie是不兼容的.
同时,回到PHP农场.
以下内容对PHP编译器有效 - 它很乐意将其转换为可执行字节代码,但是会出现运行时错误:
class Alpha {}
class Beta extends Alpha {
function sayHello() {
print "Hello";
}
}
$a = new Alpha();
$a->sayHello();
Run Code Online (Sandbox Code Playgroud)
这是因为PHP变量没有类型.编译器不知道哪个运行时类型对变量有效,因此它不会尝试强制执行它.您也没有像在Java中那样明确指定类型.有类型提示,是的,但这些只是运行时合同.以下内容仍然有效:
// reuse the classes from above
function tellToSayHello(Alpha $a) {
$a->sayHello();
}
tellToSayHello(new Beta());
Run Code Online (Sandbox Code Playgroud)
尽管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"
Run Code Online (Sandbox Code Playgroud)
这个功能有时与类型转换相混淆,但这是用词不当.类型仍然是值的属性,类型更改在运行时发生 - 而不是在编译时.
在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"
Run Code Online (Sandbox Code Playgroud)
从语法上来说,这看起来很像用静态类型语言编写类型转换器.因此,它经常与类型转换混淆,即使它仍然是运行时类型转换.
总结一下:类型转换是一种改变变量类型(而不是值)的操作.由于变量在PHP中没有类型,因此不仅无法做到,而且首先要问的是无意义的事情.
虽然不需要在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);
Run Code Online (Sandbox Code Playgroud)
所以你要做的就是将父对象传递给子对象的构造函数,然后让构造函数复制属性.您甚至可以根据需要过滤/更改它们.
//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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
它不是类型转换,但它可以满足您的需求.
这是一个更改对象类的函数:
/**
* 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)));
}
}
Run Code Online (Sandbox Code Playgroud)
如果不清楚,这不是我的功能,它来自http://www.php.net/manual/en/language.types.type-juggling.php上的"toma at smartsemantics dot com" . #50791
我重写了Josh发布的函数(由于未定义的$ new_class变量,这将会出错).这是我得到的:
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;
}
Run Code Online (Sandbox Code Playgroud)
它就像你期望一个类演员一样工作.您可以为访问类成员构建类似的东西 - 但我认为我不会需要它,所以我会留给其他人.
嘘说所有的混蛋,说"PHP不投"或"你不需要在php中投射".Bullhockey.Casting是面向对象生活的重要组成部分,我希望我能找到比丑陋的序列化黑客更好的方法.
谢谢Josh!
| 归档时间: |
|
| 查看次数: |
62004 次 |
| 最近记录: |