Php 用户定义对象的类型转换
就像我们对uuu ToString所做的那样,有没有一种方法可以定义一种用于强制转换的方法Php 用户定义对象的类型转换,php,casting,Php,Casting,就像我们对uuu ToString所做的那样,有没有一种方法可以定义一种用于强制转换的方法 $obj = (MyClass) $another_class_obj; 我不相信PHP中有重载操作符来处理这个问题,但是: <?php class MyClass { protected $_number; static public function castFrom($obj) { $new = new self(); if (is_int($obj)) {
$obj = (MyClass) $another_class_obj;
我不相信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);
不需要在php中键入cast
编辑:由于这个话题似乎会引起一些混乱,我想我应该详细说明一下
在Java这样的语言中,有两种东西可以携带类型。编译器对类型有一个概念,而运行时对类型有另一个概念。编译器类型与变量绑定,而运行时引擎跟踪值的类型(分配给变量)。变量类型在编译时已知,而值类型仅在运行时已知
如果一段输入代码违反编译器类型系统,编译器将呕吐并停止编译。换句话说,不可能编译一段违反静态类型系统的代码。这捕获了某类错误。例如,以下面一段(简化的)Java代码为例:
class Alpha {}
class Beta extends Alpha {
public void sayHello() {
System.out.println("Hello");
}
}
如果我们现在这样做:
Alpha a = new Beta();
class Alpha {}
class Beta extends Alpha {
public void sayHello() {
System.out.println("Hello");
}
}
class Charlie extends Alpha {}
Alpha a = new Charlie();
((Beta) a).sayHello();
我们可以,因为Beta
是Alpha
的子类,因此是Alpha
类型的变量a
的有效值。然而,如果我们继续这样做:
a.sayHello();
编译器会给出一个错误,因为方法sayHello
不是Alpha
的有效方法-不管我们知道a
实际上是Beta
输入类型转换:
((Beta) a).sayHello();
在这里,我们告诉编译器,变量a
在本例中应被视为Beta
。这被称为类型转换。这个漏洞非常有用,因为它允许语言中存在多态性,但显然它也是各种类型系统违规的后门。为了保持某些类型的安全性,因此存在一些限制;只能强制转换到相关的类型。在等级制度上或下。换句话说,您将无法强制转换到完全不相关的类Charlie
需要注意的是,所有这些都发生在编译器中,也就是说,它发生在代码运行之前。Java仍然可以进入运行时类型错误。例如,如果您这样做:
Alpha a = new Beta();
class Alpha {}
class Beta extends Alpha {
public void sayHello() {
System.out.println("Hello");
}
}
class Charlie extends Alpha {}
Alpha a = new Charlie();
((Beta) a).sayHello();
上述代码对编译器有效,但在运行时,您将得到一个异常,因为从Beta
到Charlie
的转换不兼容
与此同时,回到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"
(Some_Object) $variable = get_some_object($id); # This does not work, even in PHP 7.2
从语法上看,这很像用静态类型语言编写的类型转换。因此,它也经常与类型转换混淆,即使它仍然是运行时类型转换
总而言之:类型转换是一种更改变量类型(而不是值)的操作。因为变量在PHP中是没有类型的,这不仅是不可能做到的,而且首先要问的是一件毫无意义的事情。这里有一个函数来更改对象的类:
/**
* 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)));
}
}
如果不清楚,这不是我的函数,它是从“toma at smartsemantics.com”在上的一篇文章中获取的。我重新编写了Josh posted函数(由于未定义的$new_类变量,该函数将出错)。以下是我得到的:
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;
}
它的工作原理就像你期望一个班级演员的工作原理一样。您可以构建类似的东西来访问类成员,但我认为我永远都不需要它,所以我将把它留给其他人
嘘所有说“php不强制转换”或“你不需要在php中强制转换”的混蛋。曲棍球。强制转换是面向对象生活的一个重要部分,我希望我能找到一种比丑陋的序列化黑客更好的方法
谢谢你,乔希 我认为您需要键入cast来制作更好的IDE。但是php语言本身不需要类型转换,但是它支持对变量中的值进行运行时类型更改。看看自动装箱和取消装箱。这就是php固有的功能。因此,很抱歉,IDE并不比现在更好。尽管不需要在PHP中键入cast,但您可能会遇到这样一种情况,即希望将父对象转换为子对象
简单的
因此,您所要做的就是将父对象传递给子对象的构造函数,并让构造函数复制属性。您甚至可以根据需要过滤/更改它们
先进的
这不是类型转换,但它可以满足您的需要。如果您只需要为类型暗示进行转换,这就行了
if(is_object($dum_class______________)want)和&$dum_class__________________
{
//输入提示现在可以工作了
$dum_级_
(Some_Object) $variable = get_some_object($id); # This does not work, even in PHP 7.2
$variable = get_some_object($id); # We expect Some_Object to return
is_a($argument, 'Some_Object') || die('get_some_object() function didn't return Some_Object');
class One
{
protected $one = 'one';
}
class Two extends One
{
public function funcOne()
{
echo $this->one;
}
}
$foo = new One();
$foo = (Two) $foo;
$foo->funcOne();
class One
{
protected $one;
public function __construct(string $one)
{
$this->one = $one;
}
public function pub(string $par){
echo (__CLASS__ . ' - ' . __FUNCTION__ . ' - ' . $this->one . '-' .$par);
}
}
class Wrapper
{
private $obj;
public function __construct(One $obj)
{
$this->obj = $obj;
}
public function newFunction()
{
echo (__CLASS__ . ' - ' . __FUNCTION__);
}
public function __call($name, $arguments)
{
return call_user_func_array([$this->obj, $name], $arguments);
}
}
$foo = new One('one');
$foo->pub('par1');
$foo = new Wrapper($foo);
$foo->pub('par2');
$foo->newFunction();
class One
{
protected $one;
public function __construct(string $one)
{
$this->one = $one;
}
}
$foo = new One('one');
$tmp = (new class ($foo) extends One {
protected $obj;
public function __construct(One $obj)
{
$this->obj = $obj;
parent::__construct('two');
}
public function getProtectedOut()
{
return $this->obj->one;
}
} )->getProtectedOut();
echo ($tmp);
function castToTest($val): Test
{
return $val;
}
$test = castToTest(require("someFile.php"));
public static function cast($sourceObject)
{
$destinationObject = new self();
try {
$reflectedSource = new ReflectionObject($sourceObject);
$reflectedDestination = new ReflectionObject($destinationObject);
$sourceProperties = $reflectedSource->getProperties();
foreach ($sourceProperties as $sourceProperty) {
$sourceProperty->setAccessible(true);
$name = $sourceProperty->getName();
$value = $sourceProperty->getValue($sourceObject);
if ($reflectedDestination->hasProperty($name)) {
$propDest = $reflectedDestination->getProperty($name);
$propDest->setAccessible(true);
$propDest->setValue($destinationObject, $value);
} else {
$destinationObject->$name = $value;
}
}
} catch (ReflectionException $exception) {
return $sourceObject;
}
return $destinationObject;
}