strange php oop behavior, can someone explain? - php

In a nutshell: a class inherits a function from its parent. This function then gets called on the child, but appears to still have the scope of the parent class. Is this expected behavior?
Consider the following code example:
<?php
class OLTest {
private $var1 = 10;
public function getVar1() {
if (isset($this->var1)) {
return $this->var1;
} else {
return 'undefined';
}
}
public function getVar2() {
if (isset($this->var2)) {
return $this->var2;
} else {
return 'undefined';
}
}
}
class OLTest2 extends OLTest {
private $var1 = 11;
private $var2 = 20;
}
$oltest = new OLTest();
$oltest2 = new OLTest2();
echo "calling parent->getVar1\n";
echo $oltest->getVar1() . "\n";
echo "calling parent->getVar2\n";
echo $oltest->getVar2() . "\n";
echo "calling child->getVar1\n";
echo $oltest2->getVar1() . "\n";
echo "calling child->getVar2\n";
echo $oltest2->getVar2() . "\n";
?>
To my understanding, the output should be:
calling parent->getVar1
10
calling parent->getVar2
undefined
calling child->getVar1
11
calling child->getVar2
20
The actual output on my machine is:
calling parent->getVar1
10
calling parent->getVar2
undefined
calling child->getVar1
10
calling child->getVar2
undefined
To add to the confusion, a print_r($this) within either of the functions, will show that the scope is really set to the subclass, yet it's impossible to access the variable.
Can someone clear this up for me?
EDIT: I am using PHP in version 5.3.3-1ubuntu9.5.

No, the output should definetly be 10, undefined, 10, undefined.
The reason is that the variables that are private are visible only to the class defining them (not super or subclasses).
So, when child is called, its methods are defined in the parent object and when they resolve var1 or var2 they check in the scope definied for OLTest.
var2 is not accessible too because the declared var2 is only visible inside OLTest2.
To get your output, your should declare these variables protected or public.

It seems to be related to the private scope.
Try changing to protected or public anc check the results.

Yes, it is because your properties are private. The methods you are calling still belong to parent class as you haven't redefined them. To enable parent methods accessing child's properties you must make them protected in both parent and child classes:
class OLTest {
protected $var1 = 10;
public function getVar1() {
if (isset($this->var1)) {
return $this->var1;
} else {
return 'undefined';
}
}
public function getVar2() {
if (isset($this->var2)) {
return $this->var2;
} else {
return 'undefined';
}
}
}
class OLTest2 extends OLTest {
protected $var1 = 11;
protected $var2 = 20;
}
If you keep it private in parent class it won't allow child class to override that property, so the function belonging to parent class will be accessing its own private property. And if you make it private in child class it won't allow parent methods to access it.
If you still want to keep them private you'll have to copy-paste code of your methods into child class (yes, return parent::getVar1() won't work either).

You cannot "inject" private $var2 into the parent class, which is what you were trying to do.
So yes, that is normal behavior.

Because you have declared your vars private, they are totally hidden from each other. Thus the $var1 in the parent is actually a different variable from the $var1 in the child
When you call getVar1 on the parent, it uses the $var1 it sees, the one from the parent with the value 10. Similarly the parent cannot see the child's $var2, so to it the property is undefined.
When you call getVar1 and getVar2 on the child, the methods themselves are inherited from the parent class and behave exactly as they would if they were called from an object of the type OLTest

It's the scope of your private variables, try using protected
class OLTest {
protected $var1 = 10;
public function getVar1() {
return isset($this->var1) ? $this->var1:'undefined';
}
public function getVar2() {
return isset($this->var2) ? $this->var2:'undefined';
}
}
class OLTest2 extends OLTest {
protected $var1 = 11;
protected $var2 = 20;
}
$oltest = new OLTest();
$oltest2 = new OLTest2();
echo "calling parent->getVar1\n".$oltest->getVar1()."\n";
echo "calling parent->getVar2\n".$oltest->getVar2()."\n";
echo "calling child->getVar1\n".$oltest2->getVar1()."\n";
echo "calling child->getVar2\n".$oltest2->getVar2()."\n";
Results:
calling parent->getVar1
10
calling parent->getVar2
undefined
calling child->getVar1
11
calling child->getVar2
20

Related

What is the difference between these PHP variables

Can anyone tell me what is the differnce between:
class Test {
public $var; // I know this can be accessed from outside...
public function __construct($var) {
$this->var = $var; // This
$this->new_var = $var; // And this ... ? this is only internal like I would write private $new_var; ?
}
public function echoVar() {
echo $this->new_var;
}
}
There actually won't be any fundamental difference between those two - if you write to an undeclared property in PHP (from either inside or outside the class), it will dynamically create a new public property. So given the following script:
<?php
class Test {
public function __construct() {
$this->foo = 'foo';
}
}
$test = new Test;
echo $test->foo;
you'll get the output foo. See https://eval.in/632326.
In short, properties need to be explicitly declared as private or protected if you want to hide them.
You can also implement the magic methods __get and __set on your class in order to better deal with calls to read or write dynamic properties. See the manual page on overloading for more information.
I'll add comment lines to specifiy each variable.
class Test {
public $var; // I know this can be accessed from outside...
//Variable/property that can be accessed from outside the class like you mentioned.
public function __construct($var) {
$this->var = $var; // This
//$this calls a non static method or property from a class, in this case the property `public $var`
$this->new_var = $var; // And this ... ? this is only internal like I would write private $new_var; ?
//Creates a new public property in the Test class
}
public function echoVar() {
echo $this->new_var;
//echo the property new_var from Test class.
}
}
Explanation in comments
class Test {
public $var; // This is a member variable or attribute.
// Something that this class has access to
// and any of its sub-children
public function __construct($var) {
$this->var = $var; //If you mean $this then it is
// the current instance of this class see below
//If you mean $var it is a the parameter that
//is passed to the method. See below as well
$this->new_var = $var; // update: this adds a public member to the object
// essentially another $var just not easily known.
// Not sure a good use for this except confusion and chaos.
// If it were just $new_var then it is a
// scoped variable in this method
}
}
Example of $this and parameters
$testPony = new Test("pony"); //An instance of test with a parameter of pony
$testUnicorn = new Test("unicorn"); //An instance of test with a parameter of unicorn
echo $testPony->var . "<br>";
echo $testUnicorn->var . "<br>";
echo $testPony->new_var . "<br>";
echo $testUnicorn->new_var . "<br>";
echo "<pre>";
var_dump($testPony);
The above would output this:
pony
unicorn
I like pony
I like unicorn
object(Test)#49 (3) {
["var"]=>string(4) "pony"
["new_var"]=>string(11) "I like pony"
}
As a note the end dump only show public members if there were private ones it would be in the format (assume private $foo) ["foo":"Test":private]=>NULL

Get the number of time a class method has been invoked?

Let's say I have this class.
class foo{
function a(){
return $this;
}
}
And I instantiate it as:
$O = new foo();
$O->a()
->a()
->a();
Is there any way to know, in that last function ->a() how many times it was called before?
So, I could output like 'method ->a() has been called twice before this.'
I would like to find out this, without using increment values like declaring a property and then increment it increment it, everytime it is called in a function.
I am just hopping if there is a hidden feature in OOP that can provide for this solution
You can use a static variable inside the method:
class foo{
function a(){
// $count will be initialized the first time a() was called
static $count = 0;
// counter will be incremented each time the method gets called
$count ++;
echo __METHOD__ . " was called $count times\n";
return $this;
}
}
Note that static has a different meaning when used inside a method or function and it has nothing to do with static class members - although it is the same keyword. It means that the variable will be created and initialized only once when the method has been called for the first time.
However, in the example above there is no way to reinitialize that counter. If you want to do that you may introduce a parameter or something like this. Also you may not use a static variable but an object property.. There are tousand ways to do it, tell me your exact application needs I may give a more specific example....
In comments it was suggested to use a decorator for this job. I like this idea and will give a simple example:
class FooDecorator
{
protected $foo;
protected $numberOfCalls;
public function __construct($foo) {
$this->foo = $foo;
$this->reset();
}
public function a() {
$this->numberOfCalls++;
$this->foo->a();
return $this;
}
public function resetCounter() {
$this->numberOfCalls = 0;
}
public function getNumberOfCalls() {
return $this->numberOfCalls;
}
}
Usage example:
$foo = new FooDecorator(new foo());
$foo->a()
->a()
->a();
echo "a() was called " . $foo->getNumberOfCalls() . " times\n";

Is there a reason for dynamic variables to not be private?

It's possible to extend classes during runtime, and I've been playing around with it a bit, but then I stumbled upon this, which to me is strange. If I define a new variable in a private function it becomes a public variable. Shouldn't it at least be protected?
Here's the code that I've used to test this:
class FooBar {
public function FooBar() {
$this->t();
}
public function createVariable() {
$this->NewVar();
}
private function NewVar() {
$this->iam = "Hello you!";
}
private function t() {
$this->T = "ballad";
return $this->T;
}
}
$fb = new FooBar();
echo $fb->T;
echo "<br/>";
var_dump($fb);
$fb->createVariable();
echo $fb->iam;
echo "<br/>";
var_dump($fb);
echo "<br/>";
$fb->outer = "okay";
echo $fb->outer;
And as an extra, since it's possible to extend a class during runtime why isn't this possible:
function foo() {
private $this->anewvar = 0; //private is illegal.
}
PHP allows variables to be instantiated at any time without explicitly defining them.
But since you haven't defined the variable explicitly, PHP doesn't know how you want it to be scoped, and it has no way for you to tell it either, so it just goes with the safest possible option and makes it public.
If you want it scoped privately, define it as a private variable in the class definition.

assigning static var to non-static var, method to return the values not working

I'm new to PHP and practicing using static variables. I decided to grab an example that I learnt from C++ and re-write it for PHP (example from the bottom of this article).
There's a class with two private variables (one static), a constructor and a get-method. The constructor assigns the static variable's value to the second private variable, and then increments.
<?php
class Something
{
private static $s_nIDGenerator = 1;
private $m_nID;
public function Something() {
$m_nID = self::$s_nIDGenerator++;
echo "m_nID: " . $m_nID . "</br>"; //for testing, can comment this out
}
public function GetID() {
return $m_nID;
}
}
// extra question:
// static variable can be assigned a value outside the class in C++, why not in PHP?
// Something::$s_nIDGenerator = 1;
$cFirst = new Something();
$cSecond = new Something();
$cThird = new Something();
echo $cFirst->GetID() . "</br>";
echo $cSecond->GetID() . "</br>";
echo $cThird->GetID() . "</br>";
?>
Using the echo test in line 9 to see if m_nID is getting a value I see:
m_nID: 1
m_nID: 2
m_nID: 3
But these values are not being returned by the "->GetID()" calls. Any ideas why?
Edit: both replies so far have solved this, I wish I could "check" them both, so thank you! I'll leave the original code in the question as-is for any future people who have a similar problem
Your background in C++ led up to this issue, which is an easy mistake to make. In PHP, all instance (or object) variables are referenced using $this->, and static (or class) variables with self::. Based on your code:
public function GetID() {
return $m_nID;
}
Access to the private variable $m_nID should be scoped like this:
public function GetID() {
return $this->m_nID;
}
And inside your constructor:
$m_nID = self::$s_nIDGenerator++;
It should have been:
$this->m_nID = self::$s_nIDGenerator++;
Q & A
Why is there no need to put $ before m_nID when using $this->
The above two ways of referencing instance and class variables come with a very different kind of syntax:
$this is the instance reference variable and any properties are accessed using the -> operator; the $ is not repeated for the property names themselves, although they're present in the declaration (e.g. private $myprop).
self:: is synonymous to Something:: (the class name itself); it doesn't reference an instance variable and therefore has no $ in front of it. To differentiate static variables from class constants (self::MYCONST) and class methods (self::myMethod()) it's prefixed with a $.
Extra
That said, $this->$myvar is accepted too and works like this:
private $foo = 'hello world';
function test()
{
$myvar = 'foo';
echo $this->$foo; // echoes 'hello world'
}
class Something{
private static $s_nIDGenerator = 1;
private $m_nID;
public function Something() {
$this->m_nID = self::$s_nIDGenerator++;
}
public function GetID() {
return $this->m_nID;
}
}
It is interesting to note the difference between using self::$s_nIDGenerator on a static variable vs using $this->s_nIDGenerator on a static variable, whereas $this-> will not store anything.

PHP - passing variables to classes

I trying to learn OOP and I've made this class
class boo{
function boo(&another_class, $some_normal_variable){
$some_normal_variable = $another_class->do_something();
}
function do_stuff(){
// how can I access '$another_class' and '$some_normal_variable' here?
return $another_class->get($some_normal_variable);
}
}
and I call this somewhere inside the another_class class like
$bla = new boo($bla, $foo);
echo $bla->do_stuff();
But I don't know how to access $bla, $foo inside the do_stuff function
<?php
class Boo
{
private $bar;
public function setBar( $value )
{
$this->bar = $value;
}
public function getValue()
{
return $this->bar;
}
}
$x = new Boo();
$x->setBar( 15 );
print 'Value of bar: ' . $x->getValue() . PHP_EOL;
Please don't pass by reference in PHP 5, there is no need for it and I've read it's actually slower.
I declared the variable in the class, though you don't have to do that.
Ok, first off, use the newer style constructor __construct instead of a method with the class name.
class boo{
public function __construct($another_class, $some_normal_variable){
Second, to answer your specific question, you need to use member variables/properties:
class boo {
protected $another_class = null;
protected $some_normal_variable = null;
public function __construct($another_class, $some_normal_variable){
$this->another_class = $another_class;
$this->some_normal_variable = $some_normal_variable;
}
function do_stuff(){
return $this->another_class->get($this->some_normal_variable);
}
}
Now, note that for member variables, inside of the class we reference them by prefixing them with $this->. That's because the property is bound to this instance of the class. That's what you're looking for...
In PHP, constructors and destructors are written with special names (__construct() and __destruct(), respectively). Access instance variables using $this->. Here's a rewrite of your class to use this:
class boo{
function __construct(&another_class, $some_normal_variable){
$this->another_class = $another_class;
$this->some_normal_variable = $another_class->do_something();
}
function do_stuff(){
// how can I access '$another_class' and '$some_normal_variable' here?
return $this->another_class->get($this->some_normal_variable);
}
}
You need to capture the values in the class using $this:
$this->foo = $some_normal_variable

Categories