Keeping object consistence at its creation Let's assume I have 2 objects Product and Volume. 1 Product must have at least 1 Volume which means: Product ----> 1...* Volume.

I want to keep the consistence of Product at its creation, in other words, I want to block the user to create products without any volumes.

I have a ready working code, but nonetheless I want to know your opinions guys.

Here is the running code: https://3v4l.org/t7JqO#v700

Here is my code:

&lt;?php
declare(strict_types = 1);

namespace App
{
    class Product
    {
        private $id;
        private $name;
        private $volumes;

        /**
         * Product constructor.
         * @param int $id
         * @param string $name
         * @param array $volumes
         * @throws \InvalidArgumentException
         */
        public function __construct(int $id, string $name, array $volumes)
        {
            $this-&gt;id = $id;
            $this-&gt;name = $name;

            if (count($volumes) === 0) {
                throw new \InvalidArgumentException('Your product must have 1 product at least.');
            }

            $this-&gt;volumes = $this-&gt;prepareVolumes($volumes);
        }

        private function prepareVolumes(array $volumes)
        {
            foreach ($volumes as $volume) {
                $volume-&gt;setProduct($this);
            }
            return $volumes;
        }
    }

    class Volume
    {
        protected $id;
        protected $product;
        protected $description;

        public function __construct(string $description)
        {
            $this-&gt;description = $description;
        }

        public function setProduct(Product $product)
        {
            $this-&gt;product = $product;
        }
    }

    class ProductTest
    {
        public function __construct()
        {
            $volume1 = new Volume('part-1');
            $volume2 = new Volume('part-2');
            $volume3 = new Volume('part-3');

            $product = new Product(1, 'BED', [$volume1, $volume2, $volume3]);
            $invalidProduct = new Product(2, 'Table', []);
        }
    }

    return new ProductTest();
}
At first:


  Note: Strict typing is only defined for scalar type declarations, and as such, requires PHP 7.0.0 or later, as scalar type declarations
  were added in that version.


Secondly:
You are passing in an array of volumes $volumes to the __construct function when instantiating an object of class Product. But there is no confidence that each element of $volumes is an object of Volume class. Someone could put into $volumes array an arbitrary value.
I would recommend applying dependency with Volume class and pass in Product constructor only one object of Volume class (following the initial rule: "Product must have at least 1 Volume"). And then, if necessary, you will be able to add some additional 'volumes' to product object using an auxiliary method addVolume().
See the optimized version:

&lt;?php
declare(strict_types = 1);

namespace App
{
    class Product
    {
        private $id;
        private $name;
        private $volumes = [];

        /**
         * Product constructor.
         * @param int $id
         * @param string $name
         * @param array $volumes
         */
        public function __construct(int $id, string $name, Volume $volume)
        {
            $this-&gt;id = $id;
            $this-&gt;name = $name;
            $volume-&gt;setProduct($this);    
            $this-&gt;volumes[] = $volume;
        }

        public function addVolume(Volume $volume)
        {  
            $volume-&gt;setProduct($this); 
            $this-&gt;volumes[] = $volume;
        }
    }

    class Volume
    {
        protected $id;
        protected $product;
        protected $description;

        public function __construct(string $description)
        {
            $this-&gt;description = $description;
        }

        public function setProduct(Product $product)
        {
            $this-&gt;product = $product;
        }
    }

    class ProductTest
    {
        public function __construct()
        {
            $volume1 = new Volume('part-1');
            $volume2 = new Volume('part-2');
            $volume3 = new Volume('part-3');

            $product = new Product(1, 'BED', $volume1);
            $product-&gt;addVolume($volume2);
            $product-&gt;addVolume($volume3);

            $invalidProduct = new Product(2, 'Table', []);
        }
    }

    return new ProductTest();
}