Adding Length dimension to a Crate Object Consider Crate::addLength() in the following code:

class Crate
{
    protected $length, $width, $height;

    function __construct(float $length, float $width, float $height)
    {
        $this-&gt;length = $length;
        $this-&gt;width = $width;
        $this-&gt;height = $height;
    }

    function addLength(float $length): Crate
    {
        return new self($this-&gt;length + $length, $this-&gt;width, $this-&gt;height);
    }
}


I am concerned that Crate object creating a Crate object is a violation of Single Responsibility Principle (SRP).  Crate object duties is to keep dimensions of the crate.  Creating another crate object seems like introducing extra responsibilities to a class that already has responsibilities.

With that in mind, how to I make the code better?

The directions I think I can go are

1)  Is it better to just instead increase the length of the Crate?

function addLength(float $length): void
{
    $this-&gt;length += $length;
}


When doing so however, my crate becomes 'stretchy', which is typically not done in real life.  Instead, a new crate is constructed with given measurements.

Thus,

2) Is it better to instead delegate object creation to a separate class?

class CrateService
{

    function addLength(Crate $crate, float $length): Crate
    {
        return new Crate($crate-&gt;GetLength() + $length, $crate-&gt;getWidth(), $crate-&gt;getHeight());
    }
}


That seems to work, even if a little cumbersome - we basically call every crate's dimension individually and add the adder length, and create a new crate.
I see no problem, given your comment, to have a 'stretchy' crate, but in my example code below you can control whether the crate can be stretched or not.

class Crate
{
    private $length, $width, $height;
    private $resizable = true;

    function __construct(float $length, float $width, float $height)
    {
        list($this-&gt;length, $this-&gt;width, $this-&gt;height) = [$length, $width, $height];
    }

    function getDimensions(): array
    {
        return [$this-&gt;length, $this-&gt;width, $this-&gt;height];
    }

    function isResizable()
    {
        return $this-&gt;resizable;
    }

    function fixateSize()
    {
        $this-&gt;resizable = false;
    }

    function addLength(float $extraLength): float 
    {
        return $this-&gt;length += $this-&gt;isResizable() ? $extraLength : 0;
    }
}


I've added three methods; getDimensions(), isResizable() and fixateSize(). Note that there's no function to undo the fixateSize(). That is intentional: What would be the point of fixating the size if you can undo it?

I've made the dimension and resize fields private. Only the Crate class should be responsible for manipulating these. Child classes should use the methods of Crate to change them, hence the getDimensions() method.

Note how addLength() now returns the new length, and how it doesn't add the $extraLength when the crate size is fixated. Instead of returning the new length you could return a boolean, indicating whether the extra length is accepted. Another reason for not accepting the extra length could be that the crate would become too long.

I wouldn't use the CrateService class, that just overly complicated, and the addLength() method that returns a new object is just weird. The name of the method doesn't suggest this at all. A better name would have been cloneAndStretch().