0
votes

I am building a tiny PHP MVC framework and here is my folder structure

/app
  /controllers
  /models
  /views
  /templates
  /config
    /config.php
  /core
    /Controller.php
    /Router.php
    /init.php
/index.php

Inside the index.php which is the front controller I have this code to require the init.php from /app/core/init.php

index.php

<?php
require_once 'app/core/init.php'
$Router = new Router();
$Controller = new Controller();
?>

app/core/init.php

<?php
require_once 'Controller.php';
require_once 'Router.php';
?>

The init.php requires every base controller and classe in /core directory including Controller.php and Router.php and here the index.php also instantiates the classes

Every thing works fine at this point as I tested this by creating the constructor in both Controller.php and Router.php so the code in these two files will be like this

app/core/Controller.php

<?php
class Controller {
    public function __construct() {
        echo 'OK!';
    }
}
?>

app/core/Router.php

<?php
class Router {
    public function __construct() {
        echo 'OK!';
    }
}
?>

inside the index.php it echoes OK! as the classes are instantiates correctly but the problem is that when I want to include the config.php which is located in /app/config/config.php from the Controller.php located in /app/core/Controller.php with this code

<?php
class Controller {
    public function __construct() {
        require_once '../config/config.php';
    }
}
?>

Whenever I do this it returns this error

Controller::include(../config/config.php) [controller.include]: failed to open stream: No such    file or directory in C:\AppServ\www\myapp\app\core\Controller.php on line 6

and

Controller::include() [function.include]: Failed opening '../config/config.php' for inclusion (include_path='.;C:\php5\pear') in C:\AppServ\www\myapp\app\core\Controller.php on line 6

I think I used the correct location, I am working from /app/core/Controller.php and want to require /app/config/config.php. I go back one directory using ../

Then why can't I require the file?

3
Learn about autoloading. Also including stuff in a constructor is wrong on so many levels. - HamZa
why are you trying load config in the controller? your method is not right to have a working mvc - absfrm

3 Answers

2
votes

From my personal experience using relative file paths will at some point lead to headaches. So I usually use go with an absolute path to the file. This also has the advantage of being a tiny bit faster. Then if you get an inclusion error at some point it is easier to find the error since you have the whole path available.

To be able to make absolute paths I would recommend you to add a constant in your index.php file (the frontcontroller). Something like the following:

 define('ROOT_PATH', realpath(dirname(__FILE__)) . DIRECTORY_SEPARATOR);

Documentation for the functions define(), realpath() and dirname() here.

This defines a constant called ROOT_PATH that references the directory the index.php file is located in and therefore your root directory. At the same time I have appended a directory separator at the end to make it easier to write paths. To use this you would write.

require_once ROOT_PATH . 'config/config.php';

Bonus info

But if you use this approach in your controller.php class you are making it depend in that constant. To remedy this you can pass the root path as a variable in the constructor.

public function __construct($root) {...

And then use it like the following:

public function __construct($root) {

    require_once($root . 'config/config.php');

}

Hope this helps.

0
votes

I don't know what's going on, but require_once() wouldn't throw an error referring to itself as include(), because those are different functions, plus, if that's the whole code, the error line number doesn't match with your require_once() call line either, because it should be 4. Try restarting your webserver and see if it fix something, otherwise you're probably messing something up

0
votes

While AnotherGuy already gave a proper solution, I'd like to add that the behavior displayed by PHP is actually really quite weird. I set up a little include tree where script A includes B which includes C (all in seperate directories), but B will only include C if I specify a path relative to A, even though the _FILE__ constant at this point shows the path for B. I guess the calling script referred to in the documentation isn't the script calling this function as I'd expect, but rather the script initially served for the request.

I'll wholeheartedly agree with just not using relatively paths, but after years of PHP tinkering it's nice that it just never ceases to surprise to me.