有没有办法将数组转换为类属性?

6

有一种方法可以获取类属性并使用(array)强制转换。

$user = (array) get_object_vars($userObject)

但是我想知道,我没有找到将数组转换为类属性的直接方法。
假设我有一个用户类,其实现如下:
class User
{
    private $id = 0;
    private $fname = '';
    private $lname = '';
    private $username = '';
}

我有以下数组:

$user = array(
    'id'=> 2,
    'fname' => 'FirstName',
    'lname' => 'LastName',
    'username' => 'UserName'
);

我正在寻找一种类型转换,就像我们有 (object) 一样。问题是 (object) 类型转换将数组转换为 stdClass 对象,但我想要将我的数组转换为指定的类。

示例应该说明如下:(我假设PHP应该有这个功能。或者它可能已经有类似的东西,而我不知道。)

$userobj = (object User) $user;

上述语法的结果应该如下所示:
$userobj->id = $user['id'];
$userobj->fname = $user['fname'];
$userobj->lname = $user['lname'];
$userobj->username = $user['username'];

我想知道是否有直接的方法,而不是映射逻辑。寻找语言级别的技巧。

注意:我知道使用foreach可以完成上述任务。但如果PHP中有可用的直接方法,我还没有关注到(也许!)。

以下内容并不能解决我的问题: 将stdClass对象转换/强制转换为另一个类


3
你需要编写自定义方法来实现这一点。原因是对象无法处理不同的属性或未定义的属性。类似于$object->load($array)的东西。 - Yasen Zhelev
可能是重复的问题:将PHP数组转换为类变量 - Yasen Zhelev
尝试这个:https://dev59.com/pHE85IYBdhLWcg3wkkU8 - Ahmed Ziani
1
如果你正在从数据库中获取数据,大多数API都有一个fetch_object()或类似的函数,你可以在其中指定类。 - AbraCadaver
2
那么对于你的问题的直接答案是:PHP中不存在这样的东西。 - deceze
显示剩余4条评论
2个回答

1

数组并不是一个对象,因此无法使用语言结构进行转换。即使在 PHP 中也无法强制转换用户定义的对象。

因此,您必须编写自己的逻辑。有一些花哨的方法是通过 serialize() 对象,更改类名,然后再次 unserialize() 来自动化该过程。

此外,您可以使用反射编写一个强制转换函数。但是所有操作都需要用户自己的逻辑。

关于此,请参见 SO 上的这篇文章:Type casting for user defined objects

因此,如果您真的想要强制转换对象,我最终得出了这个函数(请看这里以查看其运行情况):

function cast($to, $obj)
{
    $toLength = strlen($to);
    $serializedObj = preg_replace('/^O:\\d+:"[^"]+"/', 'O:' . $toLength . ':"' . $to . '"', serialize($obj));

    $serializedObj = preg_replace_callback('/s:(\\d+):"([^"]+)";(.+?);/', function($m) use($to, $toLength) {
        $propertyName = $m[2];
        $propertyLength = $m[1];

        if(strpos($m[2], "\0*\0") === false && ($pos = strrpos($m[2], "\0")) !== false) {
            $propertyName = "\0" . $to . "\0" . substr($m[2], $pos + 1);
            $propertyLength = ($m[1] + $toLength - $pos + 1);
        }

        return 's:' . $propertyLength . ':"' . $propertyName . '";' . $m[3] . ';';
    }, $serializedObj);

    return unserialize($serializedObj);
}

$user = array(
    'id'=> 2,
    'fname' => 'FirstName',
    'lname' => 'LastName',
    'username' => 'UserName'
);

$userObj = cast(User::class, (object)$user);

print_r($userObj);

但我永远不会在生产中使用这个函数。这只是一个实验性的东西。

更新

好的,我重新考虑了Java中的类型转换方式。在Java中,实际上可以将一个对象强制转换为其子对象。你无法将任何对象转换为其他任何对象。

所以你可以在Java中这样做:

$apple = new Apple();
$macintoshApple = (MacintoshApple)$apple;

假设MacintoshApple 扩展自 Apple

但是您不能像这样转换两个不相关的对象:

$apple = new Apple();
$pear = (Pear)$apple;

非常好的函数,但是这里还有一个问题需要你回答;与“foreach”逻辑相比,性能如何? - Saurin Dashadia
我只能猜测,但从我的经验来看,我会说既不是序列化方法也不是反射方法在性能上能够超过foreach。 - TiMESPLiNTER
你说得对,我刚刚比较了一下,发现foreach方法的速度几乎是双倍。 - Saurin Dashadia

0

根据您对@AbraCadaver评论的回复,我建议您使用类似以下代码将数据库结果加载到您选择的实例化类中:

// using MySQLi
$mysqli_result = ...; // your mysqli_result object
while($class_obj = $mysqli_result->fetch_object('your_class_name')) {
    // do something
}

// using PDO
$pdo_statement = ...; // your PDOStatement object
while($class_obj = $pdo_statement->fetch_object('your_class_name')) {
    // do something
}

嗨,Mike,我的评论是希望得到类似于fetch_object的东西,但我并没有使用/获取数据库中的数据。我的示例解释得很清楚。 :) - Saurin Dashadia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接