-1

The following code works great in a simple PHP file:

class Dad
{
    protected $age = 10;
}

class Son extends Dad 
{
    public function age()
    {
        return $this->age + 10;
    }
}

$dad = new Dad();
$son = new Son();

print_r($son->age());

It prints as expected the value 20, which means the Son class was able to access the $age variable.

Now, switching this code into a Laravel project I end up with something like:

Controller:

class CustomersController extends Controller
{
    public function refresh(Request $request)
    {
        $sale = new \App\Classes\Customer\Sale;
        $sale->setItems($request->items);

        $total = new \App\Classes\Customer\Total;       
        print_r($total->getItems());
    }
}

Class Sale:

namespace \App\Classes\Customer;

class Sale 
{
    protected $items;

    public function setItems($_items)
    {
        $this->items = $_items;
    }
}

Class Total

namespace \App\Classes\Customer;

class Total extends Sale 
{
    public function getItems()
    {
        return $this->items;
    }
}

The result of print_r($total->getItems()) is array(0) {}. This means it can access the variable, but somehow it does not get the value?

I obviously check up if items was actually receiving something and if I change my setItems function into:

public function setItems($_items)
{
    $this->items = $_items;

    print_r($this->items);
}

It prints the value correctly. What am I missing?

Linesofcode
  • 5,327
  • 13
  • 62
  • 116

2 Answers2

1

What am I missing?

You are missing the basic understanding how instantiation and inheritance work. Over here you can find a comprehensive explanation about what an instance is. Ignore the Java tag, the information is completely relative to PHP as well.

Once you have the basic understanding, read the PHP basics. Afterwards, you will see the error of your ways:

class CustomersController extends Controller
{
    public function refresh(Request $request)
    {
        $sale = new \App\Classes\Customer\Sale;
        $sale->setItems($request->items);

        $total = new \App\Classes\Customer\Total;       
        print_r($total->getItems());
    }
}

Here, you create a new instance of the Sale class in $sale and a new instance of Total class in $total. While those instances are described by their relative classes, and Total inherits after Sale, they do not share any values with each other, except for the ones you declare as default. If you set a value in $sale, $total will not have the means to know about it. So, if you need to set the items, do this:

$total = new \App\Classes\Customer\Total;       
$total->setItems($request->items);

This code will work. Another approach would be to declare $items static. The static keyword "makes (properties) accessible without needing an instantiation of the class". You can read all about it here.

Be careful though, using static too much will make your code messy, unmaintainable and will make your life hell.

Kevin Kopf
  • 13,327
  • 14
  • 49
  • 66
  • Well that doesn't meet my requirements. My variable `$items` is protected to be accessible through many classes, but it is dynamic, which means it can receive multiple and different values. It seems that Child classes can only access the variable original content and not the modified/new content, am I right? – Linesofcode Jun 10 '20 at 12:56
  • Child classes can access any public/protected content of their parents if you modify it on their own instance. That's the point I made in the answer. – Kevin Kopf Jun 10 '20 at 15:14
0

Someone might be able to explain this better, but inheritance uses the parent classes definition. If you create an instance of the parent class and change a variable in it, you are not actually changing the parent class definition so the child class will still use the original definition.

To explain using your Son and Dad Class:

class Dad
{
    protected $age = 10;

    public function getsOlder()
    {
        return $this->age + 10;
    }
}

class Son extends Dad 
{
    public function age()
    {
        return $this->age + 10;
    }
}

$dad = new Dad();

$dad->getsOlder(); // $dad->age should be 20 here

// If we create a new instance of dad, the age of the new dad will be same as the class definition, 10
$stepDad = new Dad();

// Son is inheriting the class definition of the Dad class where the age is 10, NOT the $dad nor $stepDad instance
$son = new Son();

print_r($son->age()); // This will show 20 because son's age is 10 at this stage

For your laravel case, i think you are going about the wrong way if you are trying to get a total for your sale class. A total can simply be a function or an accessor of the Sale class that will return the total value of that sale. Inheritance is more for if you have different type of "Sale" that has different behaviours/properties but also common ones.

Helioarch
  • 1,158
  • 5
  • 18
  • So its not possible to access the variable `$age` (if I set a new value) in the child class? – Linesofcode Jun 10 '20 at 12:55
  • @Linesofcode That's correct! I have edit the code in the code block a little to help you understand that in that code no matter what modification you do to `$dad` instance , the class definition stays the same. So any new `Dad` instance and `Son` instance will have 10 as the starting age – Helioarch Jun 10 '20 at 14:50