Using undefined property in php class - 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?

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.

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.

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.

Related

PHP property doesn't exist but no errors thrown when used

So I came across a code like this and it makes use of one of the Bar class properties called testObj while it's not defined so I expected this to be wrong but I tested it my own and no errors:
<?php
class Foo{
public function __construct()
{
echo 'Echo From Foo';
}
}
class Bar{
public function __construct(Foo $foo)
{
$this->testObj = $foo;
}
}
$bar = new Bar(new Foo);
Why is that so? Does this have anything to do with the "Dynamic/Loose Type"ness of PHP or something else?
Properties can be defined dynamically and their visibility is defaulted to public as can be seen in the example below:
class X {
public function test()
{
$this->y = 'test';
}
}
$x = new X();
$x->test();
echo $x->y; // test
You can also do this without being in the class, so if I wanted to add another property, I could just do the following:
class X {
public function test()
{
$this->y = 'test';
}
}
$x = new X();
$x->test();
echo $x->y; // test
$x->z = 'blah';
echo $x->z; // blah
Remember, when a class in instantized it is just an object which can be manipulated as any other object.
Note: If I don't call test() in the above code, it will result it an error (undefined property) because the variable has not been defined except in the test() function.
Live Example
Repl
This is perfectly normal, you can dynamicaly assign every propteries to a PHP class without error. Event if you should declare it properly to keep track of your object structure.
If you want it to throw an error, you can use the __get magic function and ReflectionClass to determine wich property is setted and wich you can't set even if I didn't see any advantage of doing this.

PHP: Trying to get property or methods of non-object

I am trying to save an object as property in an another class, PHP throwing notices and fatal errors. Simplified version of my code:
<?php
class A {
public function a() {
// do something
}
}
$A = new A();
class B {
private $A;
public function __constructor($A) {
$this->A = $A;
}
private function b() {
if($this->A->a()) { // This line is referred by PHP
// do something
}
}
}
$B = new B($A);
You have a typo. Change __constructor to __construct and PHP will process your code correctly. Constructors in PHP are always named __construct. See the documentation for more details.

SetProperty to a class instance

I'm trying to set a property to a class instance dynamically. I've written the following:
class MyClass{
public function setProp($prop){
$this->{$prop}=$prop;
}
}
$inst= new MyClass();
$vari='123';
$inst->setProp($vari);
echo $inst->vari;
I'm expected that after $inst->setProp($vari); method invokation the $inst MyClass instance has the vari field with the 123 value. But it's not true. How to fix this?
In your case you will set property with name 123 which is not valid property. If your code was
$vari='asd';
$inst->setProp($vari);
echo $inst->asd;
You would successfully create property with name asd and the same value
Because it's getting the variable value, but not its name.
(EDIT: My previous explanation was wrong)
You'd better has a second parameter with the property name.
class MyClass{
public function setProp($name, $value){
$this->{$name}=$value;
}
}
$inst= new MyClass();
$vari='123';
$inst->setProp('vari',$vari);
echo $inst->vari;
Which ofcourse is like an overkill, if you do not have any logic around it (to be a valid setter).
Undefined properties will be set automatically
<?php
class MyClass{
}
$inst= new MyClass();
$inst->vari = 123;
echo $inst->vari;
P.S.: You will get into a trouble if you try it when the property exists and its private/protected
class MyClass{
private $vari = 100;
public function setProp($name, $value) {
$this->{$name} = $value;
}
}
$inst= new MyClass();
$vari = 123;
$inst->setProp('vari', $vari);
echo $inst->vari;
Will result into Fatal error: Cannot access private property MyClass::$vari
To access private/protected/non-existent properties you can use magic method __get(). In order to write into then, you should use __set().
class MyClass{
private $vari = 100;
public function __set($name, $value) {
$this->{$name} = $value;
}
public function __get($name) {
return $this->{$name};
}
}
$inst= new MyClass();
$inst->vari = 123;
echo $inst->vari;
However, if you don't have real reason to expose your inaccessible properties, it's not good idea to do it.

static method vs non-static method

Below are the examples of php class code that is static method and non static method.
Example 1:
class A{
//None Static method
function foo(){
if (isset($this)) {
echo '$this is defined (';
echo get_class($this);
echo ")<br>";
} else {
echo "\$this is not defined.<br>";
}
}
}
$a = new A();
$a->foo();
A::foo();
//result
$this is defined (A)
$this is not defined.
Example 2:
class A{
//Static Method
static function foo(){
if (isset($this)) {
echo '$this is defined (';
echo get_class($this);
echo ")<br>\n";
} else {
echo "\$this is not defined.<br>\n";
}
}
}
$a = new A();
$a->foo();
A::foo();
//result
$this is not defined.
$this is not defined.
I am trying to figure out what is the difference between these two Classes.
As we can see on the result of the none static method, the "$this" was defined.
But on the other hand the result on the static method was not defined even they were both instantiated.
I am wondering why they have different result since they were both instantiated?
Could you please enlighten me on what is happening on these codes.
Before we go any further: Please, get into the habbit of always specifying the visibility/accessibility of your object's properties and methods. Instead of writing
function foo()
{//php 4 style method
}
Write:
public function foo()
{
//this'll be public
}
protected function bar()
{
//protected, if this class is extended, I'm free to use this method
}
private function foobar()
{
//only for inner workings of this object
}
first off, your first example A::foo will trigger a notice (calling a non-static method statically always does this).
Secondly, in the second example, when calling A::foo(), PHP doesn't create an on-the-fly instance, nor does it call the method in the context of an instance when you called $a->foo() (which will also issue a notice BTW). Statics are, essentially, global functions because, internally, PHP objects are nothing more than a C struct, and methods are just functions that have a pointer to that struct. At least, that's the gist of it, more details here
The main difference (and if used properly benefit) of a static property or method is, that they're shared over all instances and accessible globaly:
class Foo
{
private static $bar = null;
public function __construct($val = 1)
{
self::$bar = $val;
}
public function getBar()
{
return self::$bar;
}
}
$foo = new Foo(123);
$foo->getBar();//returns 123
$bar = new Foo('new value for static');
$foo->getBar();//returns 'new value for static'
As you can see, the static property $bar can't be set on each instance, if its value is changed, the change applies for all instances.
If $bar were public, you wouldn't even need an instance to change the property everywhere:
class Bar
{
public $nonStatic = null;
public static $bar = null;
public function __construct($val = 1)
{
$this->nonStatic = $val;
}
}
$foo = new Bar(123);
$bar = new Bar('foo');
echo $foo->nonStatic, ' != ', $bar->nonStatic;//echoes "123 != foo"
Bar::$bar = 'And the static?';
echo $foo::$bar,' === ', $bar::$bar;// echoes 'And the static? === And the static?'
Look into the factory pattern, and (purely informative) also peek at the Singleton pattern. As far as the Singleton pattern goes: Also google why not to use it. IoC, DI, SOLID are acronyms you'll soon encounter. Read about what they mean and figure out why they're (each in their own way) prime reasons to not go for Singletons
Sometimes you need to use a method but you don't want call class, because some functions in a class called automatically like as __construct, __destruct,... (Magic Methods).
called class:
$a = new A();
$a->foo();
Don't called class: (just ran foo() function)
A::foo();
http://php.net/manual/en/language.oop5.magic.php

php private properties can be accessed outside

the code here outputs 20, 20, why the private property can be accessed here:
class myClass {
private $a;
public function __construct() {
$this->a = 10;
}
public function printValue() {
print "The Value is: {$this->a}\n";
}
public function changeValue($val, $obj = null) {
if(is_null($obj)) {
$this->a = $val;
} else {
$obj->a = $val; //why this works?
}
}
public function getValue() {
return $this->a;
}
}
$obj_one = new myClass();
$obj_two = new myClass();
$obj_one->changeValue(20, $obj_two);
$obj_two->changeValue($obj_two->getValue(), $obj_one);
$obj_two->printValue();
$obj_one->printValue();
any ideas?
For the purpose of encapsulation, it's important that the internals of a class be protected from access by other parts of code that must not know about the internals of the class. The class itself presumably knows about its internals and can access private properties of instances of itself just fine.
Class can always access its own properties regardless of whether they belong to the instance itself or to another instance. This works exactly as intended.
This is not an issue. You're not accessing the private property from outside, but inside the class and returning it. This basic OO.
$obj->a = $val; //why this works?
It works because you are passing an object of myClass using $obj_two and inside the class the variable $a can be accessed, which is perfectly fine
The restriction of accessing the private variable is enforced when you try something like:
$obj_two = new myClass();
echo $obj_two->a;
$obj_one->changeValue(20, $obj_two);
$obj_two->changeValue($obj_two->getValue(), $obj_one);
In both lines $obj is not null so the else part is executed. During the first call value of $this->a = 20 and during the second call when you use $obj_two->getValue() it retrieves the value of $obj_two->a which is set when you called the first function.

Categories