Adam Winter
Adam Winter

Reputation: 1914

PHP Constructors and extending parent classes

I'm coming from Java, and wanting to use the constructor of a child class the way that it works in Java, but it appears that it doesn't work like that in PHP. The constructor of the child object can't seem to overwrite the instance variable values constructed in the parent object. Here, the parent object is being used just for the common methods between multiple child classes that will extend it. The parent class will never be called on its own.

When I instantiate a new TestPackage, I just get the initialized error values from the parent class. What gives?

<?php
interface Package{
    public function getCode();
    public function decode($packageCode);
    public function getSetName();
    public function getSetNameLang();
    public function getSubsetType();
    public function getSubsetTypeLang();
    public function setSubsetType($typeCode);
    public function getPackageOptionsArray();
    public function getChoicesArray();
    public function getOptionStatus($index);
    public function setOptionStatus($index, $booleanStatus);
}
?>

ParentPackage.php

class ParentPackage implements Package{
    private int $packageCode;
    private int $subsetType;
    private String $setName;
    private String $setNameLang;
    private $packageOptionsArray;
    private $subsetTypeArray;

    public function __construct(){
        $this->packageCode = 0;
        $this->subsetType = 0;
        $this->setName = "Error: parentClass";
        $this->setNameLang = "Error: Parent Class";

        $this->packageOptionsArray = array("Error",   //too much stuff to pass
                                            "Error",  //to a constructor as a variable
                                            "Error",
                                            "Error",
                                            "Error",
                                            "Error",
                                            "Error",
                                            "Error",
                                            "Error",
                                            "Error",
                                            "Error",
                                            "Error",
                                            );
        
        $this->subsetTypeArray = array("Error: Initializer",   //16
                                        "Error: Initializer",  //32
                                        "Error: Initializer",  //48
                                        );

     //........A whole bunch more stuff that is too much to pass as a variable to a constructor
     //..... OR let's just say that I don't want to do it that way

    }

TestPackage.php

class TestPackage extends ParentPackage{

    public function __construct(){
        parent::__construct();
        $this->packageCode = 0;
        $this->subsetType = 0;
        $this->setName = "layeredarch";
        $this->setNameLang = "Layered Arch";

        $this->packageOptionsArray = array("Customized welcome sign (choice of trellis half arch or smooth half arch insert up to 25 words text)",
                                            "3 piece seating chart half arch set (print service for cards is available for a small additional fee)",
                                            "Table numbers 1-30",
                                            "Gold Card option04 with choice of Gifts & Cards sign",
                                            "5 Reserved signs",
                                            "Up to 2 Double Half Arch Small signs (Gifts & Cards, Take One, Dont Mind if I Do, In Loving Memory)",
                                            "Up to 2 Sunset Small signs (Please Sign Our Guestbook, Gifts & Cards, In Loving Memory)",
                                            "1 Double Half Arch Medium sign (Cheers, The Bar, Guestbook, or Custom Acrylic Text)",
                                            "1 Double Full Arch Medium sign (Signature Drinks, or Custom Acrylic Text)",
                                            "Unplugged Ceremony sign",
                                            "Hairpin Record Player Prop",
                                            "%22Mr & Mrs%22 Custom Head Table Keepsake is a free gift in addition to the items above"
                                            );
        
        $this->subsetTypeArray = array("Full Set",   //16
                                        "Pick Six",  //32
                                        "Pick Four" //48
                                        );

    }

Upvotes: 0

Views: 191

Answers (1)

amphetamachine
amphetamachine

Reputation: 30595

private members are local only, i.e. they cannot be read/written to via child classes. Any setter/getter in the parent class will only ever read/write from the members wrt the parent scope.

If you change the member access from private to protected it works.

PHP doesn't give an access error when the child class sets them because it's using the "dynamically-declared members" feature of PHP.

class ParentPackage implements Package {
    protected int $packageCode;
    protected int $subsetType;
    protected string $setName;
    protected string $setNameLang;
    protected $packageOptionsArray;
    protected $subsetTypeArray;
...

Less-optimal solution

This is here more as an illustration of what PHP is doing rather than an actual suggestion. :-)

Another solution would be to copy the entire getter/setter methods from the parent class into the child class, effectively switching the member scope of what they access:

// Note: Don't do this. Seriously.
class ParentPackage implements Package {
    private $packageOptionsArray;
    public function getPackageOptionsArray() { return $this->packageOptionsArray; }
}

class TestPackage extends ParentPackage {
    // Optional declaration, but without this, this property
    // is dynamically created and defaults to 'public' access.
    // NOTE! This variable is NOT the same as the one of the same name in the parent class.
    private $packageOptionsArray;
    /** Override */
    public function getPackageOptionsArray() { return $this->packageOptionsArray; }
}

This technique unfortunately can lead to some very confusing code; essentially the parent class will be reading/writing its own members, and the children will have a different member. And never the twain shall meet, leading to some very interesting but very time-consuming bugs. Don't use it.

No, just mark 'em protected and both the parent and child scopes will share the members.

Upvotes: 2

Related Questions