Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using undefined property in php class

Tags:

php

<?php
class a{
    public function out(){
        $this->test = 8;
        return $this->test;
    }
}
$b = new a();
echo $b->out();
?>

output: 8

when i run this code, output the result 8 .

but when i add __set() function, it output a notice, and not 8 output

<?php
class a{
    public function __set($property, $value) {  
    }
    public function out(){
        $this->test = 8;
        return $this->test;
    }
}
$b = new a();
echo $b->out();
?>

output:

PHP Notice: Undefined property: a::$test in /usercode/file.php on line 13

why is it happening?

like image 781
Deqin Chen Avatar asked Jan 25 '18 09:01

Deqin Chen


3 Answers

As per the docs

__set() is run when writing data to inaccessible properties.

Since you do not have anything in your __set body, the property is not created and therefore not available. You have to define the method body.

class a{
    public function __set($property, $value) {
        $this->$property = $value;
    }
    public function out(){
        $this->test = 8;
        return $this->test;
    }
}
$b = new a();
echo $b->out();

Now THAT outputs 8.

Update You are asking why the first block of code works and the second does not. Take a look at PHP source code here and you will see the explanation in the code itself.

Looks to me, that when you do not have __set() in your class and you do $this->test, PHP internally calls it's own __set(), which does exactly what it does: sets the property name to certain value.

But when you define __set() with empty body, it overrides the default internal __set() and does nothing. And that is the main reason for your code to fail - the requested property has not been set neither by your __set(), nor by the internal one.

like image 182
Alex Karshin Avatar answered Oct 04 '22 23:10

Alex Karshin


When a::out() runs, there is no $test property in the object. This is why $this->test = 8; invokes a::__set().

But a::__set() doesn't create the $test property and the next statement (return $this->test;) cannot find it and produces the notice.

You should declare the object properties in the class definition and initialize them in the constructor (if appropriate):

class a {
    private $test;               // <-- because of this, $this->test exists...

    public function __set($property, $value) {  
    }

    public function out() {
        $this->test = 8;         // ... and __set() is not invoked here
        return $this->test;
    }
}

Without __set() being defined, the statement $this->test = 8; creates the $test property of the current object if it is not already created (by its definition or by a previous assignment to it) then stores 8 into it.

When __set() is defined, any attempt to set a property that doesn't exist or it is not accessible (setting inside the class a private property inherited from the parent class or setting a protected or private property outside the class) is handled by __set(). Your implementation of __set() doesn't create the missing property and it basically turns the statement $this->test = 8; into a no-op.

like image 44
axiac Avatar answered Oct 04 '22 21:10

axiac


The following is true.

<?php
class a{
    public function __set($property, $value) {
        $this->$property = $value;
    }
    public function out(){
        $this->test = 8;
        return $this->test;
    } 
}
$b = new a();
echo $b->out();  

you should look at is php overloading

Find the answers in the manual.

like image 35
winlans Avatar answered Oct 04 '22 23:10

winlans