Why does Magento have _construct and __construct methods? - php

Is there a reason why Magento has a _construct and a __construct method? Why does the additional _construct exist? Could anything achieved by having the extra _construct method not be achieved by just calling the parent constructor in the child class?

Best answer I can find: http://www.magentocommerce.com/boards/viewthread/76027/#t282659
Basically, the root-level class (from which all other classes inherit) implements __construct, which PHP calls automatically whenever a class is constructed. Right now, this root-level class simply calls _construct, which contains the actual code.
Say you have this set-up:
class BaseClass {
function __construct() {
print "In BaseClass constructor\n";
doSomethingReallyImportant();
}
}
class SubClass extends BaseClass {
function __construct() {
print "In SubClass constructor\n";
}
}
$obj = new BaseClass();
//"In BaseClass constructor"
//something really important happens
$obj = new SubClass();
//"In SubClass constructor"
//important thing DOESN'T happen
PHP doesn't automatically call the parent class constructors, so doSomethingReallyImportant never gets called. You could require that subclass constructors call parent::__construct(), but that's easy to forget. So Magento has subclasses override _construct:
class BaseClass {
function __construct() {
doSomethingReallyImportant();
_construct();
}
function _construct() {
print "In BaseClass constructor\n";
}
}
class SubClass extends BaseClass {
function _construct() {
print "In SubClass constructor\n";
}
}
$obj = new BaseClass();
//something really important happens
//"In BaseClass constructor"
$obj = new SubClass();
//something really important happens
//"In SubClass constructor"
PHP doesn't detect a constructor in SubClass, so it calls BaseClass's constructor. This allows BaseClass to doSomethingReallyImportant before calling SubClass's overridden _construct.

To Marco: it is wrong to override __construct() method like this in Magento. The reason is - all classes inherit it from Varien_Object and it has this code:
#File: lib/Varien/Object.php
public function __construct()
{
//...snip...
$args = func_get_args();
if (empty($args[0]))
{
$args[0] = array();
}
//...snip...
}
//...
With the __construct using your code, those arguments don’t get passed through.
You really have to use Benesch's code:
class SubClass extends BaseClass {
function _construct() {
print "In SubClass constructor\n";
}
}
Read more about this in Magento Block Lifecycle Methods by Alan Storm

Edit: sorry, missed the the difference between _construct and __construct in your question. I think the Magento programmers have tried to make it easier to override the constructor without the risk of their own constructor not being called anymore. The _construct method on Varien_Object is empty so it doesn't matter if it's not called from subclasses.
This is just how PHP implements constructors and destructors for classes. There's nothing Magento specific about it.
In other languages the constructor is usually implemented with a method having the same name as the class itself and the constructor usually has a tilde (~) in front of the method name baring the same name as the class. For some reason the PHP people have implemented it this way although PHP also seem to support constructors and destructors with the class name (link).
A class does not have to have a constructor and/or destructor, especially when you subclass another class. If you do override the constructor or destructor then you need to call the constructor or destructor of the overridden class manually by calling it on parent::, like:
class SubClass extends BaseClass {
function __construct() {
parent::__construct();
// Your code
}
function __destruct() {
// Your code
parent::__destruct();
}
}

Single underscore construct (_construct) is used to avoid overriding the actual constructor with double underscore (__construct).
Example: vendor/magento/framework/Model/ResourceModel/AbstractResource.php
/**
* Constructor
*/
public function __construct()
{
/**
* Please override this one instead of overriding real __construct constructor
*/
$this->_construct();
}
/**
* Resource initialization
*
* #return void
*/
abstract protected function _construct();

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.

PHP - Object instantiation context - Odd behaviour - Is it PHP bug?

I am not asking a typical question about why some code failed, yet I am asking about why it worked.It has worked with me while coding, and I needed it to fail.
Case
a base abstract class with a protected constructor declared abstract
a parent class extends the abstract class with public constructor (Over ridding)
a child class extends the very same abstract class with a protected constructor
abstract class BaseClass {
abstract protected function __construct();
}
class ChildClass extends BaseClass {
protected function __construct(){
echo 'It works';
}
}
class ParentClass extends BaseClass {
public function __construct() {
new ChildClass();
}
}
// $obj = new ChildClass(); // Will result in fatal error. Expected!
$obj = new ParentClass(); // that works!!WHY?
Question
Parent class instantiates child class object, and it works!!
how come it does?
as far as I know,object cannot be instantiated if its constructor declared protected, except only internally or from within any subclasses by inheritance.
The parent class is not a subclass of the child class,it doesn't inherit a dime from it ( yet both extend the same base abstract class), so how come instantiation doesn't fail?
EDIT
This case only happens with an abstract BaseClass that has also an abstract constructor.If BaseClass is concerete, or if its protected constructor is not abstract, instantiation fails as expected.. is it a PHP bug?
For my sanity, I need really an explanation to why PHP behaves this way in this very specific case.
Thanks in advance
Why it works?
Because from inside ParentClass you have granted access to the abstract method from BaseClass. It is this very same abstract method which is called from ChildClass, despite its implementation is defined on itself.
All relies in the difference between a concrete and an abstract method.
You can think like this: an abstract method is a single method with several implementations. On the other hand, each concrete method is a unique method. When it has the same name than its parent, it overrides the parent's one (it does not implement it).
So, when declared abstract, it is always the base class method which is called.
Think about a method declared abstract: Why the signatures of different implementations can't differ? Why can't the child classes declare the method with less visibility?
Anyway, you have just found a very interesting feature. Or, if my understanding above is not correct, and your expected behaviour is the truly expected behaviour, then you have found a bug.
Note: the following was tested with PHP 5.3.8. Other versions may exhibit different behavior.
Since there isn't a formal specification for PHP, there isn't a way of answering this from the point of view of what should happen. The closest we can get is this statement about protected from the PHP manual:
Members declared protected can be accessed only within the class itself and by inherited and parent classes.
Though the member may be overridden in ChildClass (keeping the "protected" specifier), it was originally declared in BaseClass, so it remains visible in descendants of BaseClass.
In direct opposition to this interpretation, compare the behavior for a protected property:
<?php
abstract class BaseClass {
protected $_foo = 'foo';
abstract protected function __construct();
}
class MommasBoy extends BaseClass {
protected $_foo = 'foobar';
protected function __construct(){
echo __METHOD__, "\n";
}
}
class LatchkeyKid extends BaseClass {
public function __construct() {
echo 'In ', __CLASS__, ":\n";
$kid = new MommasBoy();
echo $kid->_foo, "\n";
}
}
$obj = new LatchkeyKid();
Output:
In LatchkeyKid:
MommasBoy::__construct
Fatal error: Cannot access protected property MommasBoy::$_foo in - on line 18
Changing the abstract __construct to a concrete function with an empty implementation gives the desired behavior.
abstract class BaseClass {
protected function __construct() {}
}
However, non-magic methods are visible in relatives, whether or not they're abstract (most magic methods must be public).
<?php
abstract class BaseClass {
abstract protected function abstract_protected();
protected function concrete() {}
}
class MommasBoy extends BaseClass {
/* accessible in relatives */
protected function abstract_protected() {
return __METHOD__;
}
protected function concrete() {
return __METHOD__;
}
}
class LatchkeyKid extends BaseClass {
function abstract_protected() {}
public function __construct() {
echo 'In ', __CLASS__, ":\n";
$kid = new MommasBoy();
echo $kid->abstract_protected(), "\n", $kid->concrete(), "\n";
}
}
$obj = new LatchkeyKid();
Output:
In LatchkeyKid:
MommasBoy::abstract_protected
MommasBoy::concrete
If you ignore the warnings and declare magic methods (other than __construct, __destruct and __clone) as protected, they appear to be accessible in relatives, as with non-magic methods.
Protected __clone and __destruct are not accessible in relatives, whether or not they're abstract. This leads me to believe the behavior of abstract __construct is a bug.
<?php
abstract class BaseClass {
abstract protected function __clone();
}
class MommasBoy extends BaseClass {
protected function __clone() {
echo __METHOD__, "\n";
}
}
class LatchkeyKid extends BaseClass {
public function __construct() {
echo 'In ', __CLASS__, ": \n";
$kid = new MommasBoy();
$kid = clone $kid;
}
public function __clone() {}
}
$obj = new LatchkeyKid();
Output:
In LatchkeyKid:
Fatal error: Call to protected MommasBoy::__clone() from context 'LatchkeyKid' in - on line 16
Access to __clone is enforced in zend_vm_def.h (specifically, ZEND_CLONE opcode handler). This is in addition to access checks for methods, which may be why it has different behavior. However, I don't see special treatment for accessing __destruct, so there's obviously more to it.
Stas Malyshev (hi, Stas!), one of the PHP developers, took a look into __construct, __clone and __destruct and had this to say:
In general, function defined in base class should be accessible to all
[descendents] of that class. The rationale behind it is that if you define
function (even abstract) in your base class, you saying it will be
available to any instance (including extended ones) of this class. So
any descendant of this class can use it.
[...] I checked why ctor behaves differently, and it's because parent ctor
is considered to be prototype for child ctor (with signature
enforcement, etc.) only if it's declared abstract or brought from the
interface. So, by declaring ctor as abstract or making it part of the
interface, you make it part of the contract and thus accessible to all
hierarchy. If you do not do that, ctors are completely unrelated to each
other (this is different for all other non-static methods) and thus
having parent ctor doesn't say anything about child ctor, so parent
ctor's visibility does not carry over. So for ctor is not a bug. [Note: this is similar to J. Bruni's answer.]
I still think it's most probably a bug for __clone and __destruct.
[...]
I've submitted bug #61782 to track the issue with __clone and __destruct.
EDIT: constructors act differenlty... It's expected to work even without abstract classes but I found this test that tests the same case and it looks like it's a technical limitation - the stuff explained below doesn't work with constructors right now.
There's no bug. You need to understand that access attributes work with objects' context. When you extend a class, your class will be able to see methods in BaseClass' context. ChildClass and ParentClass both in BaseClass context, so they can see all BaseClass methods. Why do you need it? For polymorphism:
class BaseClass {
protected function a(){}
}
class ChildClass extends BaseClass {
protected function a(){
echo 'It works';
}
}
class ParentClass extends BaseClass {
public function b(BaseClass $a) {
$a->a();
}
public function a() {
}
}
No matter what child you pass into ParentClass::b() method, you'll be able to access BaseClass methods (including protected, because ParentClass is BaseClass child and children can see protected methods of their parents). The same behaviour applies to constructors and abstract classes.
I wonder if there isn't something buggy w/ the abstract implementation under the hood, or if there is a subtle issue going on that we're missing. Changing BaseClass from abstract to concrete produces the fatal error you're after though (classes renamed for my sanity)
EDIT: I agree w/ what #deceze is saying in his comments, that it is an edge case of abstract implementation and potentially a bug. This is at least a work-around that provides the expected behavior albiet some ugly technique (feigned abstract base class).
class BaseClass
{
protected function __construct()
{
die('Psuedo Abstract function; override in sub-class!');
}
}
class ChildClassComposed extends BaseClass
{
protected function __construct()
{
echo 'It works';
}
}
// Child of BaseClass, Composes ChildClassComposed
class ChildClassComposer extends BaseClass
{
public function __construct()
{
new ChildClassComposed();
}
}
PHP Fatal error: Call to protected ChildClassComposed::__construct()
from context 'ChildClassComposer' in
/Users/quickshiftin/junk-php/change-private-of-another-class.php on
line 46

PHP superclass and subclass

A simple question, does the following make sense ?
Class B extends Class A
class A constructor:
function __construct(){
//do something
}
Class B constructor:
function __construct(){
parent::__construct();
}
Is there any significant advantage to implementing the child constructor at all in this case?
I can only think of :
The entire code for class B will be more "complete" in structure
Would be interesting to know if there is any significant advantages in coding or in structuring etc.
The only time you want to invoke your parent constructor from your subclass (child class) is when you want to add custom code in your constructor.
In your example you can leave out the __construct() method altogether in Class B.
However you might want to do something like this:
class A {
function __construct() {
run_a_function();
$this->set = "a variable";
}
}
class B {
function __construct() {
run_a_function_specific_to_class_b();
$this->set = "a variable specific to class b";
// now call the parent constructor
parent::__construct();
}
}
No. If all your constructor (or any method for that matter) does is call the parent method of the same name, then there's no advantage whatsoever. Just more lines of code.
A local constructor overrides its parent:
<?php
class Blog extends CI_Controller {
public function __construct()
{
parent::__construct();
// Your own constructor code
}
}
?>
If you have a __construct() method in the child class you must call the parent constructor explicitly.
If you have no desire to run anything in the child constructor, do not specify the constructor method in the child and the parents constructor will be called automatically.

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

Categories