Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP - class does not call constructor of extended class, while it works fine in an other class

Tags:

php

My problem:

So, I have a class called 'Home' and it extends the class 'Controller' the controller class requires all models in a constructor. This works fine.

Now I have a second class called 'Login' It also extends the class 'Controller' but, it does not call the constructor, and I am confused why it is not calling the constructor in this class.

I have found a workaround and that is to make a constructor in the Login class with Parent::__construct() when I do that, everything works fine.

But I am working why it does work in the Home class, and its not working in the Login class.

Some info:

The home controller: (the one without any problems)

Backtrace when I do not force to call the constructor of the extended class:

0 Core\Controller->__construct() called at [/var/www/html/site.luukwuijster.eu/core/Router.php:26] #1 App->__construct() called at [/var/www/html/site.luukwuijster.eu/public/index.php:5]

Backtrace when I am forcing to call the constructor of the extended class:

0 Core\Controller->__construct() called at [/var/www/html/site.luukwuijster.eu/app/controllers/home.php:12] #1 Home->__construct() called at [/var/www/html/site.luukwuijster.eu/core/Router.php:26] #2 App->__construct() called at [/var/www/html/site.luukwuijster.eu/public/index.php:5]

The Login controller: (the one with the problems)

When I am not forcing to call the constructor of the extended class:

Fatal error: Uncaught Error: Class 'App\User' not found in /var/www/html/site.luukwuijster.eu/app/controllers/login.php:21 Stack trace: #0 /var/www/html/site.luukwuijster.eu/core/Router.php(26): Login->login() #1 /var/www/html/site.luukwuijster.eu/public/index.php(5): App->__construct() #2 {main} thrown in /var/www/html/site.luukwuijster.eu/app/controllers/login.php on line 21

Backtrace when I am forcing to call the constructor of the extended class:

Core\Controller->__construct() called at [/var/www/html/site.luukwuijster.eu/app/controllers/login.php:11] #1 Login->__construct() called at [/var/www/html/site.luukwuijster.eu/core/Router.php:26] #2 App->__construct() called at [/var/www/html/site.luukwuijster.eu/public/index.php:5]

As you can see, it works fine when I force to call the constructor, but When I dont force it, it only works in the Home class. (Home controller)

Code:

Home controller:

use App\User;
use Core\Controller;
use Core\DB;

class Home extends Controller
{
    public function test()
    {
        return User::name();
    }
}

Login Controller:

use App\User;
use Core\Controller;
use Core\DB;

class Login extends Controller
{

    //This is the constructor I was talking about to force the calling of 
    //the constructor in the extended class.
    public function __construct()
    {
        parent::__construct();
    }

    public function login()
    {
        return User::name();
    }

}

Extended class (controller)

namespace Core;

class Controller
{
    public $database;

    function __construct()
    {

        //I have put this here to see the backtrace.
        debug_print_backtrace();

        $this->database = new DB();

        foreach (glob('../app/models/*.php') as $model){

            require_once $model;

        }
    }

Router.php I've put this in here because when I do not force the calling of the constructor on the extended class it gets called on rule 26 in here. ($this->controller = new $this->controller;)

class App
{

    protected $controller = 'home';
    protected $method = 'index';
    protected $parameters = [];
    protected $a = 0;

    public function __construct()
    {
        $url = $this->Url();

        if(file_exists('../app/controllers/'. $url[0] .'.php')){

            $this->controller = $url[0];
            unset($url[0]);
        } else {
            if (isset($url[0]))
            die(view('error404'));
        }

        require_once '../app/controllers/'. $this->controller .'.php';

        $this->controller = new $this->controller;

        if (isset($url[1])){
            if (method_exists($this->controller, $url[1])){
                $this->method = $url[1];
                unset($url[1]);
            }else{
                die(view('error404'));
            }
        }

        $this->parameters = $url ? array_values($url) : [''];

        echo call_user_func_array([$this->controller, $this->method], $this->parameters);

    }

    public function Url()
    {
        if(isset($_GET['url'])){
            $url = filter_var(rtrim($_GET['url'], '/'), FILTER_SANITIZE_URL);
            $exploded_url = explode('/', $url);
            return $exploded_url;
        }
    }
}

My questions:

Why is it working fine in the Home controller, and not in the Login Controller?

And what do I have to do to make it work the same way in the Login Controller?

I hope everything is clear, and if you need more code or info you can ask me in the comments.

like image 946
Luuk Wuijster Avatar asked Jan 12 '17 14:01

Luuk Wuijster


2 Answers

According to the manual:

For backwards compatibility with PHP 3 and 4, if PHP cannot find a __construct() function for a given class, it will search for the old-style constructor function, by the name of the class. Effectively, it means that the only case that would have compatibility issues is if the class had a method named __construct() which was used for different semantics.

As you have a login() method in your Login class, php will use that as the constructor. Note that function names are case-insensitive.

Also note that this behaviour is deprecated in php 7 but has not yet been removed.

like image 50
jeroen Avatar answered Oct 01 '22 11:10

jeroen


As per the manual 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. 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).

Class Login has a construct thus the parent construct is not implicitly called. It my must be called explicitly.

like image 42
Andrei Avatar answered Oct 01 '22 11:10

Andrei