php 动态对象的数组

mklgxw1f  于 2023-01-29  发布在  PHP
关注(0)|答案(2)|浏览(116)

我正在尝试做一些非常基本的数据库Map转换,我从数据库中获取数据,然后尝试将数组转换为任意类的示例。这应该是动态的,以便无论输出对象类/属性如何,我都可以使用相同的函数。
假设我有案例1:

$student = [
            'name'    => 'Jhon',
            'surname' => 'Wick',
            'age'     => 40
        ];
        
        class Student{
            private string $name;
            private string $surname;
            private int $age;

            ... getter and setters
        }

案例2:

$car = [
          'manufacturer' => 'Toyota',
          'model' => 'one of their model',
          'commercialName' => 'the name'
        ];
        class Car{
            private $manufacturer;
            private $model;
            private $commercialName;
            
            // Getter and Setter
        }

我想把$student数组的var转换成Student示例,或者把$car转换成Car,我该怎么做呢?我知道我可以用类似这样的方法来做:

$funcName = 'get' . ucfirst($camelCaseName);
        if (method_exists($this, $funcName)) {
            $funcValue = $this->$funcName();
    }

但是我正在寻找一些更现代的东西,比如使用反射。什么是最好的方法?什么是有效的解决方案?
为了给予更多的信息,这是WordPress $wpdb对象的扩展所需要的。如果可能的话,我不想使用公共类属性,因为我可能需要在某些情况下实际调用类setter来更改其他类的值。让我们假设像给出出生日期这样的东西应该计算年龄

1sbrub3j

1sbrub3j1#

正如我在评论中已经说过的,你所需要的只是水合的过程。来自Laminas的男孩和女孩得到了一个维护良好的包,叫做laminas/laminas-hydrator,它可以为你做这项工作。
举个简单的例子:

<?php

declare(strict_types=1);

namespace Marcel;

use Laminas\Hydrator\ClassMethodsHydrator;
use Marcel\Model\MyModel;

$hydrator = new ClassMethodsHydrator();

// hydrate arry data into an instance of your entity / data object
// using setter methods
$object = $hydrator->hydrate([ ... ], new MyModel());

// vice versa using the getter methods
$array = $hydrator->extract($object);

你的方法并没有那么错。至少它的方向是正确的。在我看来,你不应该使用私有属性。你期望使用私有属性有什么样的好处?它们只会带来缺点。想想你的模型的扩展。受保护的属性做同样的工作,只是通过getter和setter访问属性。受保护的属性更容易处理。

<?php

declare(strict_types=1);

namespace Marcel;

class MyDataObject
{
    public ?string $name = null;
    public ?int $age = null;

    public function getName(): ?string
    {
        return $name;
    }
    
    public function setName(?string $name): void
    {
        $this->name = $name;
    }

    public function getAge(): ?int
    {
        return $this->age;
    }

    public function setAge(?int $age): void
    {
        $this->age = $age;
    }
}

class MyOwnHydrator
{
    public function hydrate(array $data, object $object): object
    {
        foreach ($data as $property => $value) {
            // beware of naming your properties in the data array the right way
            $setterName = 'set' . ucfirst($property);
            if (is_callable([$object, $setterName])) {
                $object->{$setterName}($value);
            }
        }

        return $object;
    }
}

// example
$data = [
    'age' => 43,
    'name' => 'Marcel',
    'some_other_key' => 'blah!', // won 't by hydrated
];

$hydrator = new MyOwnHydrator();
$object = new MyDataObject();

$object = $hydrator->hydrate($data, $object);

这是你能得到的最简单的水合器。它迭代数据数组,创建setter方法名,并检查它们是否可调用。如果是,值将通过调用setter方法水合到对象中。最后你将得到一个水合对象。
但是要小心。这个解决方案有一些绊脚石需要考虑。你的数据数组的键必须和你的数据对象或实体的属性完全一样命名。当你想在你的数组中使用下划线分隔的键,但是你的对象属性是驼峰大小写时,你必须使用一些命名策略,另一个问题可能是类型提示。如果示例有生日,并且只接受DateTime示例,而您的数据数组只包含生日字符串"1979-12-19",该怎么办?如果您的数据数组包含子数组,在n:m关系中应该被水合的东西
所有这些都已经在menetiond laminas Package 中完成了。如果你不需要所有那些花哨的东西,按照你的第一个想法,建立你自己的补水器。)

5lhxktic

5lhxktic2#

我建议删除setter/getter并使用readonly属性:

class Car{
    public function __construct(
        public readonly string $manufacturer,
        public readonly string $model,
        public readonly string $commercialName,
    );
}

...

new Car(...$car);

相关问题