Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any way to define the structure of Array or Object in PHP?

My question is basically exactly the same as the title says.

I was playing with TypeScript for a while now and there's a simple way to define the structure of the Object which is defining properties inside the Interface. I know that PHP does not support the properties in Interfaces, but is there any way to somehow define the structure of the Object (without using some abstract class) I'm passing or at least the Array (which keys need to be presented inside).

What I mean exactly is:

// 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) {}
}

Hope I explained it well.

like image 837
Dawid Zbiński Avatar asked Oct 30 '25 09:10

Dawid Zbiński


1 Answers

As you said, there is no concept in PHP, that does exactly what you want. There is an ArrayObject class, that would fit your demands of an object with a loose amount of members.

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;
    }
}

}

Example 1: Populate object with array

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

The builder returns an object with exact the same properties as the array had keys. All the properties contain the values the array has. You can iterate over the new object with foreach or an Iterator object.

Example 2: Populate object with another object

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

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

With PHP nearly all objects are iterable. That means you can iterate over the properties of one object and pass them to our ArrayObject instance.

Common approach of hydration with PHP

There is another approach in PHP which is called hydration. It is a bit more complex than the shown example but pretty handy, if you got it.

// 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;
    }
}

This is our data model (entity) of the type car. Our Car inherits from an interface. This is just for type hinting reasons in the hydrator. Our car has one property called horsepower. Of course a car can have more properties. But this is just for example. ;)

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;
    }
}

This is our small hydrator example. This class does, what your builder does. But in a more specific way. It takes an entity and hydrates it with the given data, if it matches a method of the entity.

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

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

The advantage of hydration is simple. You only have models with known properties. That 's pretty safe and you know at any time, what your model can do for you. It would be senseless, that a car has a rudder for example. In this case a car only got what a car got. Like in the example the car only takes the horsepower member of the array.

like image 150
Marcel Avatar answered Nov 01 '25 06:11

Marcel



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!