6
<?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?

7
  • 2
    Maybe check the manual? Commented Jan 25, 2018 at 9:23
  • First define $test variable in constructor and then assign $this->test="8"; hope it will work Commented Jan 25, 2018 at 9:29
  • 1
    Because that's what __set does. By default, PHP will create properties on the fly. If you've defined __set and it doesn't then set the property within the method, then the property won't exist, and will raise a notice when you try and read it. Commented Jan 25, 2018 at 9:30
  • 1
    I have no idea where line 13 is Commented Jan 25, 2018 at 9:30
  • @Scuzzy sorry,in “return $this->test;” Commented Jan 25, 2018 at 9:38

3 Answers 3

10

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for your answer. I understand what you said. But I want to know why my first program can run successfully. Is there any official explanation?
@DeqinChen I actually updated my answer, linking to PHP source code as well, so that you could see the reason for yourself.
6

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.

3 Comments

Thank you for your answer. I understand what you said. But I want to know why my first program can run successfully. Is there any official explanation?
@DeqinChen I updated the answer. Also read the documentation of __set().
__set IS invoked but it does not do anything, therefore, nothing is set. Thus the warning on the return.
2

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.

1 Comment

Thank you for your answer. I understand what you said. But I want to know why my first program can run successfully. Is there any official explanation?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.