Overriding property type (class) with other type (class that is extending the first one) in PHP7

Viewed 91

So, I have defined some data structures as php classes with properties only (similar syntax to C/C++ struct). To be type strict in an easy way and have properties common for all the structures in one place - I figured out to define first basic structure as abstract class - it should never be instantiated, and all the "really used" structures will be extending it. Working example:

// Parent struct def: Common data for all the shapes, not meant to be instantiated
abstract class Shape {
    public int $posX, $posY;
    public string $color;
}

// Real structure def: I would like to use this one in code a real structure
class Rectangle extends Shape {
    public int $width, $height;
}

Then, I tried to define classes for working with these structures. Concept was very similar: basic abstract class with features common for all the structures, and one child class extending it for each structure. Continuing previous working example:

abstract class ShapeRenderer {
    public Shape $shapeData;

    public function SetShapeData(Shape $shapeData) {
        $this->shapeData = $shapeData;
    }
}

class RectangleRenderer extends ShapeRenderer {
    public Rectangle $shapeData; // fatal error line

    public function SetShapeData(Rectangle $shapeData) { // warning here
        $this->shapeData = $shapeData;
    }
}

// init these variables for some testing after
$rect = new Rectangle();
$rect->width = 10;

$render = new RectangleRenderer();
$render->SetShapeData($rect);

Sadly, I cannot override type of inherited property $shapeData from abstract Shape to real one which is extending it - Rectangle (line with comment "fatal error line") gives:

Fatal error: Type of RectangleRenderer::$shapeData must be Shape (as in class ShapeRenderer)

So I commented that line. Still same error was happing when I did override param type from Shape to more strict Rectangle in ShapeRenderer method SetShapeData. Changing parent method to abstract one without a body in ShapeRenderer resulted in exchanging fatal error for a warning:

Warning: Declaration of RectangleRenderer::SetShapeData(Rectangle $shapeData) should be compatible with ShapeRenderer::SetShapeData(Shape $shapeData)

The code seems to be working, I can access $render->shapeData->width dirrectly just fine, but when i try to var_dump whole $render->shapeData it says that it's of type Shape and doesn't have property width. So it's clearly not the good solution

Is there any way to handle it other than:

declare property $shapeData without specyfing its type, only once - in common abstract class ShapeRenderer remove declaration of $shapeData in common abstract class ShapeRenderer (+ all code accessing it there), and declare it only in every child class (using any type) ? Both ways doesn't sound right to me

0 Answers
Related