i was wondering why there is no $parent->function(); syntax in php, but instead we can use parent::function(); which looks like it's used inside a static class. Am i missing some php oop basics?
I admit it seems strange -- and you didn't miss anything in the manual ^^
But :
Generally, when the child class re-defines a method that's already defined in the parent class, you want the child's method to totally override the parent's one
except for __construct, I admit -- that's probably why it's said explicitly in the manual that you have to call the parent's __construct method yourself.
Generally speaking, when working with non-static methods, you'll just use $this to call methods in the same instance of either the child or the parent class ; no need to know where the method actually is.
Using parent:: works fine, even if it looks like a static call
And here's an example of code showing parent:: works fine :
class Father {
public function method() {
var_dump($this->a);
}
}
class Son extends Father {
protected $a;
public function method() {
$this->a = 10;
parent::method();
}
}
$obj = new Son();
$obj->method();
You'll get this output :
$ /usr/local/php-5.3/bin/php temp.php
int(10)
Which shows that the method in the parent class has access to $this and the properties defined in the child class.
Well, parent actually references the static parent class - there is no reason to assume there is an instantiated $parent only because there exists a $child, and even if there were, $child would not have access to $parent.
Finally, an instance where the usual class dog extends animal OOP explanations don't work! :)
Because using $parent assumes that you have actually instantiated the parent class.
If your syntax suggest worked, it would mean everytime you instantiated one object, you were instantiating 2 or more objects.
In PHP, every variable must contain a string, integer(or other numeric format), array, object, or resource. $this contains an object, and it just happens to be the object that you are currently inside.
In order to create $parent, you would have to put an object inside $parent. You parent class is technically not instantiated, so it cannot be assigned to a variable.
BTW parent::function(); has access to all of $this.
Hence, this works
class Test
{
public function test()
{
echo $this->testing_var;
}
}
class OtherTest
{
public function run()
{
$this->testing_var = "hi";
Test::test(); // echos hi
}
}
And this will error if it is used outside a class, and will tell you it should be declared static.
Test::test();
Related
This question already has answers here:
Is subclass inherits private members from parent class? [duplicate]
(2 answers)
Closed 5 years ago.
Accept my apologies for being beginner for OOP,
according to the below code :
Class Test{
private $name = "youhana";
function setPrivatePropFromInside(){
$this->name = "mina";
}
function getPrivate(){
var_dump(__CLASS__);
echo $this->name ;
}
}
Class Test2 extends Test {
}
$obj2 = new Test2();
$obj2->getPrivate();
My Question is that Is Inheritance means to copy from parent to child or the child gain access to the parent visible members?
let me describe why I have confusion by mentioning my thoughts with both of the question members :
In case its a copy, so the invoking the method getPrivate from the child object must return null because the private members will not be copied from the parent to the child, and also the CLASS constant must return Test2 not TEST in case the Inheritance means copying.
so the code mentioned above would equals :
Class Test{
private $name = "youhana";
function getPrivate(){
var_dump(__CLASS__);
echo $this->name ;
}
}
Class Test2 extends Test {
function getPrivate(){
var_dump(__CLASS__);
echo $this->name ;
}
}
In case Inheritance means to gain access to the parent visible members, that doesn't refer or point to the concept of inheritance (the children get the characteristics of the parent) despite this concept is logically correct with the results upon executing the mentioned code snippet.
I Read more than 20 References and I still have the confusion, and again accept my apologies for being beginner searching for the correct approach.
Note that: I asked a question Here but after studying more references, I have been returned back to the confusion again, so I need a solid answer.
It's nothing to do with "copying".... a class defines methods and properties together with a visibility indicating from where those methods and properties can be accessed.
When one class extends another, then you are creating an inheritence hierarchy or tree, or a set of class contexts.
When you instantiate a child class, you are actually instantiating an object that inherits that full tree.
When you call a method against that instance, it looks to see if that method exists (and is accessible) in the child class definition. If so, it executes it in that context: if not, it looks to see if the method exists in the parent class; and if so, will execute it in that context.
When a method executes in a specific context within the hierarchy of class extensions, it has access to everything visible in that context. Private properties are only accessible in the context where they are defined/the class where they are defined; but methods in that context/class have access to those private properties.
If (as in this case) your public getters and setters exist in the same class/context as the private property, then those methods have access to the private property (because they are in the same class/context), and can be used to access it from outside of that context because the getters/setters themselves are public.
Is Inheritance means copy from parent to child or the child gain
access to the parent visible members?
The child gain access to the visible members of parent class. Also, you get flexibility to override the feature (method) of parent class.
I think your confusion comes from thinking that
private $name = "youhana";
is a static value which exists in class declaration. In any case, that is just a shorthand for declaring variable values in constructor so even if inheritance "copy" from parent its a wrong example to show that. What you should be asking is: do static properties get copied from the parent? Static properties exists in class declaration and any modifications are visible to all objects of that class.
php docs on static properties
Answer is no. Only reference to parent's value is passed.
I wrote a simple example to illustrate
<?php
class Foo
{
public static $my_static = 'foo';
public function staticValue() {
return self::$my_static;
}
public function modifyFooStatic(){
return self::$my_static .= '+';
}
}
class Bar extends Foo
{
public function fooStatic() {
return self::$my_static;
}
public function modifyBarStatic(){
return self::$my_static .= '-';
}
}
$foo = new Foo();
$foo->modifyFooStatic();
print $foo->staticValue() . "\n"; // foo+
$bar = new Bar();
$bar->modifyBarStatic();
print $bar->fooStatic() . "\n"; // foo+-
?>
As you can see both child and parent modifies the same variable even if child calls it with sellf::$my_static
I am really going crazy with this problem.
I am not able to call a method from the parent class in a static method of a child class..
This is what I tried but it does not work..
class custom extends service {
private $service;
function __construct() {
parent::__construct();
$this->service = new service;
}
public static function activematches($callback) {
$select_by_user = parent::$db->select('matches', '*', array('user_id' => $user_id,
if (count($select_by_user) == 0 && count($select_by_opponent) == 0)
parent::$check->send('11');
else
$this->service->make($callback['request'], $callback['data']);
}
When I call $this->service I get:
Fatal error: Using $this when not in object context
I tried making that as static, I tried putting the same method in the child class by calling the parent method parent::method, but nothing...
I am new to OOP, any help?
For access within a static invocation the property must be defined static as well
protected static $services;
From there you need to reference within your static methos as either.
self::$services
or
static::$services
Referencing self in this context will refer to $services property where the reference is defined. static will reference the property from the class context that the reference was invoked on. For more information see what the manual has to say about late static binding
UPDATE
Based on the fact that custom extends service in this case I doubt this is what you are really after. A class definition like :
class custom extends service {
public function activematches($callback, $user_id) {
$select_by_user = $this->db->select('matches', '*', array('user_id' => $user_id));
if (count($select_by_user) == 0 && count($select_by_opponent) == 0)
$this->check->send('11');
else
$this->make($callback['request'], $callback['data']);
}
}
May be closer to what you want.
If the parent method, make is not static:
You can't call a non-static method from the parent class from a static method of the child class. Have you considered making the child method not-static? I think that's your best option here.
If the parent method make is static:
parent::make($callback['request'], $callback['data']);
But this is called Late Static Bindings which was introduced in PHP 5.3.0. It won't work in older versions, so be careful with that.
Fatal error: Using $this when not in object context
This is actually answer for your question. The specific of static members of class is - you can use them without making an object. $this - reference for object, in which context method was called.
So try to look on problem in this way - in static member you don't have any $this.
You can only use static members of parent class in this way - self::method.
Or, you can actually create an object on parent class and use any "dynamic" method in "dynamic" notation, but this will make you even more crazy later, believe me)
Sorry for constantly re-editing my question but looks like this is the only way to ask it properly.
My original problem is the following pseudo-code (a controller and it's parent) isn't working as i would like to:
class Parent {
var $data = array();
public function __construct( OtherClass $otherClass ) {
$this->data = $otherClass->getData(); //contains some => thing
$this->init($otherClass->getClassName());
}
public function init( $className ) {
new $className; //new Child
}
public function __get( $name ) {
return array_key_exists($name, $this->data) ? $this->data[$name] : null;
}
}
class Child extends Parent {
public function __construct() {
echo $this->some; //won't return 'thing';
}
}
fireeyedboy helped me a lot (thank you) and pointed out Zend_Controller_Action is doing what i want but i can't understand how they do it?
Original question
I know there was some similar questions here but i cannot dump them. Also i know i can reverse the whole process so i can initialize Child first then call parent::__construct but this seems unwanted for me. How can i access Parent variables easily in my case?
Update:
Let me clarify a little bit. Child is an arbitrary controller. Parent is the mother of all controllers. Many frameworks are doing the same but controllers can utilize their parent controllers variables, methods or objects without calling parent::__construct (and therefore filling child class constructors with unnecessary arguments). I don't like to rewrite any of these frameworks but i'd like to understand how they're operating.
Your child class doesn't call parent constructor. Here's a fix:
class Child extends Parent {
public function __construct() {
parent::__construct();
echo $this->some;
}
}
Update: Parent classes' constructors aren't called automatically in PHP. See the documentation:
Note: Parent constructors are not
called implicitly if the child class
defines a constructor. In order to run
a parent constructor, a call to
parent::__construct() within the child
constructor is required.
So what you're asking does not happen. Either you have misinterpreted the class structure or how they operate. Note that PHP also supports legacy constructor naming (at least until 5.3.3): If there is no __construct() method in a class, PHP assumes the constructor is named after the class (ie. class Foo { function Foo() {}) treats the Foo() method as constructor).
Injecting ANYTHING using controller's construct is generally a BAD PRACTICE! Problem lies in your design. What kind of object is OtherClass? Is it DB adapter? Is it ACL? Is it some helper class?
If you need external class in your controller I suggest using action helpers. That's what they are created for ;) Or create an action helper that will fetch this OtherClass from somewhere when needed.
You should NEVER use __construct() to do any of your dirty work. That's what init() is used for. But it has no params. And there is a reason for that - again - you should not inject dependencies like this ;)
Update:
Note your class uses discouraged PHP4 member variable definition syntax. Try replacing your var with protected.
The problem is that your Child class does not call the base constructor.
Incidentally, Parent is not a valid class name in PHP. I have changed the class names for clarity. See below:
class ChildClass extends ParentClass {
public function __construct() {
parent::__construct(/* what goes here? */);
echo $this->some;
}
}
However, note the what goes here? part: your base class requires a reference to an OtherClass instance to be constructed. Therefore, since ChildClass IS-A ParentClass, it also needs to get such an instance somehow. You will need to either add a parameter to ChildClass::__construct and forward the value to parent::__construct, or somehow figure out a default value yourself.
I am extending one of the SPL (Standard PHP Library) classes and I am unable to call the parent's constructor. Here is the error I am getting:
Fatal error: Cannot call constructor
Here is a link to the SplQueue's documentation: http://www.php.net/manual/en/class.splqueue.php
Here is my code:
$queue = new Queue();
class Queue extends SplQueue {
public function __construct() {
echo 'before';
parent::__construct();
echo 'I have made it after the parent constructor call';
}
}
exit;
What could prevent me from calling the parent's constructor?
SplQueue inherits from SplDoublyLinkedList. Neither of these classes defines a constructor of its own. Therefore there's no explicit parent constructor to call, and you get such an error. The documentation is a little misleading on this one (as it is for many SPL classes).
To solve the error, don't call the parent constructor.
Now, in most object-oriented languages, you'll expect the default constructor to be called if there isn't an explicit constructor declared in a class. But here's the catch: PHP classes don't have default constructors! A class has a constructor if and only if one is defined.
In fact, using reflection to analyze the stdClass class, we see even that lacks a constructor:
$c = new ReflectionClass('stdClass');
var_dump($c->getConstructor()); // NULL
Attempting to reflect the constructors of SplQueue and SplDoublyLinkedList both yield NULL as well.
My guess is that when you tell PHP to instantiate a class, it performs all the internal memory allocation it needs for the new object, then looks for a constructor definition and calls it only if a definition of __construct() or <class name>() is found. I went to take a look at the source code, and it seems that PHP just freaks out and dies when it can't find a constructor to call because you told it explicitly to in a subclass (see zend_vm_def.h).
This error gets thrown, usually, when the parent class being referenced in parent::__construct() actually has no __construct() function.
If you want to call the constructor of the nearest ancestor, you can loop through the ancestors with class_parents and check with method_exists if it has a constructor. If so, call the constructor; if not, continue your search with the next nearest ancestor. Not only do you prevent overriding the parent's constructor, but also that of other ancestors (in case the parent doesn't have a constructor):
class Queue extends SplQueue {
public function __construct() {
echo 'before';
// loops through all ancestors
foreach(class_parents($this) as $ancestor) {
// check if constructor has been defined
if(method_exists($ancestor, "__construct")) {
// execute constructor of ancestor
eval($ancestor."::__construct();");
// exit loop if constructor is defined
// this avoids calling the same constructor twice
// e.g. when the parent's constructor already
// calls the grandparent's constructor
break;
}
}
echo 'I have made it after the parent constructor call';
}
}
For code reuse, you could also write this code as a function that returns the PHP code to be evaled:
// define function to be used within various classes
function get_parent_construct($obj) {
// loop through all ancestors
foreach(class_parents($obj) as $ancestor) {
// check if constructor has been defined
if(method_exists($ancestor, "__construct")) {
// return PHP code (call of ancestor's constructor)
// this will automatically break the loop
return $ancestor."::__construct();";
}
}
}
class Queue extends SplQueue {
public function __construct() {
echo 'before';
// execute the string returned by the function
// eval doesn't throw errors if nothing is returned
eval(get_parent_construct($this));
echo 'I have made it after the parent constructor call';
}
}
// another class to show code reuse
class AnotherChildClass extends AnotherParentClass {
public function __construct() {
eval(get_parent_construct($this));
}
}
You may hack it like this:
if (in_array('__construct', get_class_methods(get_parent_class($this)))) {
parent::__construct();
}
but it's helpless.
just declare constructor explicitly for every class. it's the right behavior.
I got the same error. I have solved it by defining an empty constructor in the parent class. That way other classes don't have to define it. I think it's cleaner approach.
If you still need to call the constructor you can do this.
if (is_callable('parent::__construct')) {
parent::__construct();
}
There was an interesting question in a practice test that I did not understand the answer to. What is the output of the following code:
<?php
class Foo {
public $name = 'Andrew';
public function getName() {
echo $this->name;
}
}
class Bar extends Foo {
public $name = 'John';
public function getName() {
Foo::getName();
}
}
$a = new Bar;
$a->getName();
?>
Initially, I thought this was produce an error because static methods can not reference $this (atleast in PHP5). I tested this myself and it actually outputs John.
I added Foo::getName(); at the end of the script and did get the error I was expecting. So, what changes when you call a static method from within a class that extends the class you're calling from?
Would anyone mind explaining in detail exactly what is going on here?
Foo::getName() is using an older PHP4 style of scope resolution operator to allow an overridden method to be called.
In PHP5 you would use parent::getName() instead
It's useful if you want to extend, rather than completely override the behaviour of the base class, e.g. this might make it clearer
class Bar extends Foo {
public $name = 'John';
public function getName() {
echo "My name is ";
parent::getName();
}
}
If you call the static method bound to the other object, the method is executed in the context of the current object. Which allows access to the $this-object.
Better way to call the superclass-method from inside the subclass would be:
parent::getName();
$this to the object in whose context the method was called. So: $this is $a->getName() is $a. $this in $fooInstance->getName() would be $fooInstance. In the case that $this is set (in an object $a's method call) and we call a static method, $this remains assigned to $a.
Seems like quite a lot of confusion could come out of using this feature. :)
When you call $a->getName() you're referencing a specific object, $a, which is of class Bar and so returns "John".
Foo::getName() isn't valid outside the function because there's no specific object.
I'm not sure it works in PHP, but if you cast the object to the superclass as in (Foo)$a->getName() then you'd get "Andrew" as your result. You'd still be talking about the specific object ($a) but in this case of type Foo. (Note you wouldn't generally want to do this)
Sometimes programmers are better at explaining things in code than in English!
The first thing going on here is the concept of overloading. When you instantiate Bar, it's getName() method overloads the method of the same name in Foo.
Overloading is a powerful and important part of OOD.
However, it is often useful to be able to call the version of a method that exists in the Parent class (Foo).
Here's an example:
class Dog
{
public function getTag()
{
return "I'm a dog.";
}
}
class Skip extends dog
{
public function getTag()
{
return Dog::getTag() . " My name is Skip.";
// I'm using Dog:: because it matches your example. However, you should use parent:: instead.
}
}
$o = new Skip();
echo $o->getTag(); // Echo's: "I'm a dog. My name is Skip."
Clearly this is a very parochial example but it illustrates a point.
Your base class is the most general implementation of a Type. In this case, it's "Dog." You want to put information in this base class that is common to all instances of that Type. This prevents duplication in each of the Derived classes (like "Skip").
Your script is taking advantage of this feature, perhaps inadvertently.