有没有办法在PHP中定义Array或Object的结构?

时间:2017-09-21 11:26:11

标签: php arrays object php-7

我的问题基本上与标题所说的完全相同。

我现在玩TypeScript已经有一段时间了,这是一种定义Object结构的简单方法,它定义了Interface中的属性。我知道PHP不支持Interfaces中的属性,但有没有办法以某种方式定义Object的结构(不使用一些抽象类)我传递或至少是数组(需要呈现哪些键)内侧)。

我的意思是:

// I already sanitized that this method returns the exact same structure every time 
$data = $this->storage->get($some); 
// here I'm passing the data I obtained to my Builder
Builder::createFromArray($data); 
// or
Builder::create($data);

class Builder {
    public static function createFromArray(\ArrayOfSomeType $array) {}
    public static function create(\ObjectOfSomeTypeWithPropertiesSpecified $obj) {}
}

希望我解释得很清楚。

2 个答案:

答案 0 :(得分:1)

正如你所说,PHP中没有概念,它完全符合你的要求。有一个ArrayObject类,可以满足您对具有大量成员的对象的需求。

class Builder {
    public function create(iterable $data) : \ArrayObject {
        $object = (new \ArrayObject())->setFlags(\ArrayObject::ARRAY_AS_PROPS);
        foreach ($data as $key => $value) {
            $object->offsetSet($key, $value);
        }

        return $object;
    }
}

}

示例1:使用数组填充对象

$object = Builder::create([ 'bla' => 'blubb', 'yadda' => 'blubb' ]);
var_dump($object->bla);

构建器返回一个与数组具有完全相同属性的对象。所有属性都包含数组所具有的值。您可以使用foreachIterator对象迭代新对象。

示例2:使用其他对象填充对象

$class = new \stdClass();
$class->propertyA = 'B';
$class->propertyB = 'B';

$object = Builder::Create($class);
var_dump($object->propertyA);

使用PHP几乎所有对象都是可迭代的。这意味着您可以迭代一个对象的属性并将它们传递给我们的ArrayObject实例。

使用PHP进行水合作用的常用方法

PHP中还有另一种称为水合作用的方法。它比显示的示例稍微复杂一些,但是非常方便,如果你得到它。

// your entity / data model
class Car implements EntityInterface {
    protected $horsepower;

    public function getHorsepower() : int
    {
        if ($this->horsepower === null) {
            $this->horsepower = 0;
        }

        return $this->horsepower;
    }

    public function setHorsepower(int $horsepower) : self
    {
        $this->horsepower = $horsepower;
        return $this;
    }
}

这是我们的汽车类型的数据模型(实体)。我们的汽车继承了一个界面。这仅用于水化器中的类型提示原因。我们的车有一个名为马力的房产。当然,汽车可以拥有更多的属性。但这仅仅是例如。 ;)

class ClassMethodsHydrator
{
    public function hydrate(array $data, EntityInterface $entity) : EntityInterface {
        foreach ($data as $key => $value) {
            $methodName = 'set' . ucwords(strtolower($key));
            if (method_exists($entity, $methodName) {
                $entity->{$methodName}($value);
            }
        }

        return $entity;
    }
}

这是我们的小型水化器示例。这个类确实是你的构建器所做的。但是以更具体的方式。它需要一个实体并使用给定的数据对其进行水合,如果它与实体的方法匹配。

$entity = (new Hydrator())->hydrate(
    [ 
        'horsepower' => 172,
        'notexistingproperty' => 'bla', 
    ],
    new Car()
);

var_dump($entity->getHorsepower()); // 172

水合作用的优点很简单。您只有具有已知属性的模型。这非常安全,您随时都知道,您的模型可以为您做什么。例如,汽车有方向舵是没有意义的。在这种情况下,汽车只能得到一辆汽车。就像在示例中一样,汽车只接受阵列的马力成员。

答案 1 :(得分:0)

我认为你可以通过在界面中创建getter和setter来强制使用。而不是

$item->something;

你可以使用

$item->getSomething();