Inheritance problem: calling parent construct function in subclass - php

I have a class named Display which extends class Layout, which extends class DOMDocument. I get: Fatal error: Call to a member function loadHTMLFile() on a non-object. Code as follows:
In index.php :
$dom = new Display();
$dom->displayData();
In Display.php :
class Display extends Layout {
public function displayData(){
$dom = parent::__construct();
$dom->loadHTMLfile("afile.html");
echo $dom->saveHTML();
}
}
My question is: When I call parent::__construct() , isn't this the same as using "new DOMDocument", since the Display class extends Layout and DOMDocument?Thanks

__construct() is a magic method that is called when you instantiate the object.
Calling it is not the same as using the new operator.
In my experience, I have only ever used parent::__construct() inside of the __construct() of a subclass when I need the parent's constructor called.

If you have the loadHTMLfile function in your parent class, the subclass will inherit it. So you should be able to do:
class Display extends Layout {
public function displayData(){
$this->loadHTMLfile("afile.html");
echo $this->saveHTML();
}
}

It is not the same because constructor in php doesn't return anything

You typically call the parent's constructor inside the subclass's constructor. You're calling it in the displayData() method. It is only necessary to call the parent's constructor explicitly in the subclass constructor if you do additional work in the subclass constructor. Inheriting it directly without changes means you needn't call the parent constructor.
Calling the parent constructor will not return a value (object), as instantiating the object would.

Related

extended class constructor not fired when child class is called using call_user_func_array

I have a quite strange issue and I don't know if this is due to call_user_func_array or not.
Testing on PHP 5.4
Current setup
I have, for example, an AuthController class that extends a base controller named Controller:
class AuthController extends Controller
{
public function login() {
return Response::json(array('error' => false, 'message' => 'I\'m in AuthController#login'));
}
}
In the extended Controller class, I have a constructor that sets up, for example, a database connection (I have a var_dump + exit added for testing purposes):
class Controller
{
protected $db;
protected function __construct() {
$database = Config::env('database');
var_dump($database);
exit;
}
}
Now to call the AuthController, I'm using call_user_func_array
call_user_func_array(array($controller, $route['action']), $data);
Now what should have happened:
What should have happened is that Controller's constructor should have fired, produced a dump on screen and exited the execution.
Instead:
Instead I'm actually getting the response from AuthController's login method Response::json().
The Controller's constructor never gets fired.
I am having a difficult time understanding why it doesn't work since the PHP manual states that constructors get fired on every new object instance and if a parent class has a constructor and the child class doesn't overwrite it, the parent class constructor is called automatically.
Does call_user_func_array not fire parent class constructors autmatically or have I misunderstood something about PHP constructor entirely?
I'll take a stab in the dark here, and say that you're actually doing this:
call_user_func_array(array('AuthController', 'login'), $data);
In other words, you're not passing an instance to call_user_func, you're just passing the string 'AuthController'. That means your method will get called statically. If you had error reporting and/or strict error reporting enabled, you should see a notice warning you about calling non-static methods statically.
The problem is (probably) that you're never actually instantiating your class, so no constructor is ever run. call_user_func won't instantiate it for you. You'll need to do that yourself:
call_user_func_array(array(new $controller, $route['action']), $data);
// ^^^
As PHP Document at http://php.net/manual/en/language.oop5.decon.php
PHP 5 allows developers to declare constructor methods for classes. Classes which have a constructor method call this method on each newly-created object, so it is suitable for any initialization that the object may need before it is used.
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. If the child does not define a constructor then it may be inherited from the parent class just like a normal class method (if it was not declared as private).
Example #1 using new unified constructors
<?php
class BaseClass {
function __construct() {
print "In BaseClass constructor\n";
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "In SubClass constructor\n";
}
}
class OtherSubClass extends BaseClass {
// inherits BaseClass's constructor
}
// In BaseClass constructor
$obj = new BaseClass();
// In BaseClass constructor
// In SubClass constructor
$obj = new SubClass();
// In BaseClass constructor
$obj = new OtherSubClass();
?>
Hope this will explain you about use of parent class constructor in child class.
also you can refere http://php.net/manual/en/function.call-user-func-array.php , here they mentioned how to call parent class function in call_user_func_array.
Example:
call_user_func_array(array($this, 'parent::__construct'), $args);
Edit 1
See below example:
class BaseClass {
protected function __construct() {
print "In BaseClass constructor<br />";
}
}
//class SubClass extends BaseClass {
// function __construct() {
// parent::__construct();
// print "In SubClass constructor<br />";
// }
//}
class OtherSubClass extends BaseClass {
// inherits BaseClass's constructor
function test(){
echo 'in test';
}
}
call_user_func_array(array('OtherSubClass', 'test'), array()); //
// In BaseClass constructor
$obj = new OtherSubClass(); //produce fatel error
output:
Strict Standards: call_user_func_array() expects parameter 1 to be a valid callback, non-static method OtherSubClass::test() should not be called statically in /var/www/html/test/test1.php on line 22
in test
Fatal error: Call to protected BaseClass::__construct() from invalid context in /var/www/html/test/test1.php on line 24
So if string give in call_user_func_array function then it is producing out put but with strict standard error, and while creating new object of the class producing fatal error.
Remember that the constructor is a special method called when a new object is created. call_user_func_array() does not call any constructor because it doesn't create any new object.
call_user_func_array(array($controller, $route['action']), $data);
From your question I assume $controller is an object of type AuthController. It is already created at the moment when you pass it to call_user_func_array(). It's constructor was called when the object was created.
But wait a minute? What constructor? The class AuthController doesn't define any constructor. It inherits the parent class constructor that is protected. Because it is not public it cannot be called and the object is not created; the script throws a fatal error and exits.
You can either change the visibility of Controller::__construct() to public (this way both classes can be instantiated and the constructor of Controller runs for both). Or, if you want to keep class Controller not instantiable for some reason you define a public constructor for class AuthController that calls the protected constructor of class Controller to do the job:
class AuthController extends Controller
{
public function __construct()
{
parent::__construct();
}
// other methods here...
}

why do we still need parent constructor when controller class extends a parent controller?

I'm a beginner in CodeIgniter and OOP. I was reading a page of CI tutorial here. I found something that made a question in my mind.
Look at this code:
<?php
class News extends CI_Controller {
public function __construct()
{
parent::__construct();
$this->load->model('news_model');
}
I think if we made a class that extends CI_Controller, we assume it must have all methods and properties in its parent class (Although we can override them). So, why there is parent::__construct(); in the code?
__construct() is the constructor method of a class. It runs if you declare a new object instance from it. However, if a class implemented its own __construct(), PHP would only run the constructor of itself, not of its parent. For example:
<?php
class A {
public function __construct() {
echo "run A's constructor\n";
}
}
class B extends A {
public function __construct() {
echo "run B's constructor\n";
}
}
// only B's constructor is invoked
// show "run B's constructor\n" only
$obj = new B();
?>
In this case, if you need to run class A's constructor when $obj is declared, you'll need to use parent::__construct():
<?php
class A {
public function __construct() {
echo "run A's constructor\n";
}
}
class B extends A {
public function __construct() {
parent::__construct();
echo "run B's constructor\n";
}
}
// both constructors of A and B are invoked
// 1. show "run A's constructor\n"
// 2. show "run B's constructor\n"
$obj = new B();
?>
In CodeIgniter's case, that line runs the constructor in CI_Controller. That constructor method should have helped your controller codes in some way. And you'd just want it to do everythings for you.
To answer your question directly from the Code Iginiter documentation:
The reason this line is necessary is because your local constructor will be overriding the one in the parent controller class so we need to manually call it.
http://ellislab.com/codeigniter/user-guide/general/controllers.html#constructors
Extension used for all classes.
__construct() used for that class that you use.
Classes which have a constructor method call this method on each newly-created object, so it is suitable for any initialization that the object may need before it is used.
I believe the need of calling the parent constructor/method is a code smell, known as Call super. Besides the error-sensitivity (forgetting this call, you can get unexpected results), it's procedural instead of OOP. After all, the order of statements can lead to unexpected results too.
Read more here: https://martinfowler.com/bliki/CallSuper.html
Inheritance is being used via the keyword extends. The parent class could be setting some values when its constructor is being called. If the parent constructor is not called the values are not set and the child class will not get those values.
Example:
class Super {
protected $a;
public function __construct(){
$this->a = 'Foo';
}
}
class Child extends Super{
protected $b = 'Bar';
public function __construct() {
parent::__construct();
echo $this->a;
}
}
$x = new Child();
Here, the class Child would echo out nothing if the parent constructor was not called.
So in Codeigniter the parent class is probably setting some values that are of help to its children when you call its constructor and those values are only available to its children if the parent constructor is called.

Are parent constructors called if a child class does NOT define a constructor?

In the PHP Constructors and Destructors documentation it states
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.
But what if the child class does not call a constructor, will the parent constructor still be called? Or should we create a constructor that calls the parent constructor anyway?
IE:
class BaseClass {
function __construct() {
print "In BaseClass constructor\n";
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct();
}
}
Maybe this was sort of obvious but did some looking around, and a direct answer to this question surprisingly wasn't very easy to find so here it is:
If the child class does NOT define a constructor then the parent constructor will be called.
In the example below $obj will still call the constructor from BaseClass because SubClass never called a constructor.
class BaseClass {
function __construct() {
print "In BaseClass constructor\n";
}
}
class SubClass extends BaseClass {
//I do not have a constructor :(
}
$obj = new SubClass();
Take into account a constructor is a method that can be overridden as any other method. If the parent class has a constructor, all its children classes will inherit that constructor. If a child overrides the constructor, this will be used when creating new objects and parent's constructor is not called implicitly. If the child does not override the constructor, the parent's constructor will be used. This concept applies to multiple inheritance.

If I don't define a constructor for a subclass, can I use the constructor of the superclass directly?

Are constructors inherited or do they belong to the class they are defined in? I only have seen examples with constructors of subclasses which call superclass' constructors. This is my current code, which can give some hint about what's going on. (I will change the code according to your replies. If I can use the constructor of the superclass, I won't define a constructor for each subclass and call superclass' constructor from each.
abstract class view
{
public $vieverid;
function __construct($viewerid) {
$this->viewer = $viewerid;
}
}
class viewactor extends view{
function __construct($viewerid) {
$this->viewerid = $viewerid;
}
According to my understanding, PHP doesn't auto-call parent's constructor if child constructor is defined. Otherwise it does.
In child constructor you have to call parent's constructor manually.
abstract class view
{
public $vieverid;
function __construct($viewerid) {
$this->viewer = $viewerid;
}
}
class viewactor extends view{
function __construct($viewerid) {
parent::__construct($viewerid); // manual call
// do your stuff here...
$this->viewerid = $viewerid;
}
parent::__construct(params); use for calling superclass constructor
PHP4
PHP doesn't call constructors of the base class automatically from a
constructor of a derived class. It is your responsibility to propagate
the call to constructors upstream where appropriate.
PHP5
PHP doesn't call constructors of the base class if new constructor defined.
If you define a constructor for derived class
It is your responsibility to propagate
the call to constructors upstream where appropriate.
parent::__construct(params)
Constructors
abstract class view
{
public $vieverid;
function __construct($viewerid) {
$this->vieverid= $viewerid;
}
}
class viewactor extends view{
function __construct($viewerid) {
parent::__construct($viewerid);
// Extra code if you want
}
}
class viewactor_construct extends view{
// Works in PHP5
}
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.
See here

PHP Inheritance Question

If I have the following class:
class foo {
function __construct() {
// Some code
}
}
And then use inheritance to create:
class bar extends foo {
// Some code
}
When I instantiate class 'bar', will it automatically execute the __construct method from 'foo' or do I need to do something else to get that method to execute?
From the manual:
Note: Parent constructors are not
called implicitly if the child class
defines a constructor.
While the documentation doesn't state it explicitly, the inverse of this sentence is also true, i.e., parent constructors are called implicitly if the child class does not define a constructor. Therefore, in your example, instantiating bar would call foo::__construct automatically.
it works, the constructer from the parent class will be inherited.
if you define a new constructor in the instaciated class, it will override the constructor function of the parent class. if you still want to execute the parent constructer you should include
parent::__construct();
in the constructer of thje isntanciated class
The __construct will carry over, yes.
The issue comes when you want to add something to that function, which is when the parent class comes in handy.
class bar extends foo {
$this->doSomethingElse();
parent::__construct();
}
Of course when you extend a class, the subclass inherits all of the public and protected methods from the parent class.

Categories