Handling Included Files

Ensuring that including class files with the wrong path fails gracefully.

By Bob Ray  |  December 10, 2024  |  4 min read
Handling Included Files

In the previous article, we put our functions inside a class and included the class file with a line like this:

include MODX_CORE_PATH . 'components/mycomponentname/model/mymathfunctions.class.php';
$math = new MyMathFunctions();

The problem with this code is that if the file being included is missing or at a different location, PHP will issue a warning message. Even if the display of PHP warnings is turned off (as it should be for a production site), the second line above will throw a PHP Fatal Error telling you that it can't find the class. In this article, we'll look at a more graceful way of handling the problem.

Solutions

If you're sure that warning messages won't be displayed, you can just check to make sure the class is available before trying to instantiate the object.

include MODX_CORE_PATH . 'components/mycomponentname/model/mymathfunctions.class.php';

if (! class_exists('MyMathFunctions')) {
    /* Handle the error with a nice looking message
       or return an error condition to a higher level */
} else {
    $math = new MyMathFunctions();
}

If your code will be distributed to others, you can't be sure warnings won't be displayed. In that case, you can suppress them by prepending the @ token to the include call, which (in theory) suppresses all error messages:

@include MODX_CORE_PATH . 'components/mycomponentname/model/mymathfunctions.class.php';

if (! class_exists('MyMathFunctions')) {
    /* Handle the error with a nice looking message
       or return an error condition to a higher level */
} else {
    $math = new MyMathFunctions();
}

Including the MODX Config File

Rather than using the class_exists method, it's a little faster to check for something that should exist if the file was included successfully. If you are writing some standalone code, you might want access to the MODX constants like MODX_BASE_PATH or MODX_ASSETS_PATH. This is usually done by first including the config.core.php file, which contains the path to the MODX core, then including the config.inc.php file. With no error checks that looks something like this:

include dirname(dirname(dirname(__FILE__))) . '/config.core.php';
include MODX_CORE_PATH . 'config/config.include.php';

The PHP dirname() function returns the path of the file inside the parentheses. By nesting multiple dirname() functions, you can "walk" up the tree to the MODX root and find the config.core.php file. The __FILE__ constant contains the full path of the current file. The number of nested dirname() calls you need depends on how far below the MODX root the current file is located. My code editor, PhpStorm, actually tells you whether the file you're referencing exists (if not, it will be highlighted). You can just keep adding dirname() calls until the highlighting disappears. It will also autocomplete both dirname() and __FILE__ for you.

It's good form to make sure you have the files you want before proceeding with your code. That might look like this:

@include dirname(dirname(dirname(__FILE__))) . '/config.core.php';
if (! defined('MODX_CORE_PATH')) {
    die('Could not find config.core.php');
}

@include MODX_CORE_PATH . 'config/config.include.php';

if (! defined('MODX_ASSETS_PATH')) {
    die('Could not find config.inc.php');
}

/* If we made it here, everything is OK */

If the config.core.php file is included successfully, the MODX_CORE_PATH constant will be defined. If the config.inc.php file is included successfully, the MODX_ASSETS_PATH constant will be defined. We can test for the existence of those two constants to see if the files were found and included properly.

Another method is to check for the file's existence before including or requiring it:

if (! defined ("MODX_CORE_PATH")) {
    if (file_exists(MODX_CORE_PATH . 'config/config.include.php') {
        include MODX_CORE_PATH . 'config/config.include.php';
    } else {
        echo "Could not find config.inc.php";
    }
}

Since PHP 4, the dirname() function has a shorter version in which the second argument to dirname() indicates the number of levels to go up. This eliminated the need to write "dirname" more than once. So our code above:

@include dirname(dirname(dirname(__FILE__))) . '/config.core.php';

Could be replaced with this:

@include dirname(__FILE__, 2) . '/config.core.php';

To keep older code from breaking, both methods will still work.

One Last Improvement

Our include statement for the config.inc.php file is not quite correct. It will work in almost all cases, but MODX gives users the option of renaming the config file by altering the MODX_CONFIG_KEY definition found in the config.core.php files. Our code will only work if the config file has its default name: config.inc.php. To be certain of finding the config file, Our second include statement should look like this:

@include MODX_CORE_PATH . 'config/' . MODX_CONFIG_KEY . '.inc.php';

Coming up

In my last few articles we've looked at handling included and required files and dealing with re-declaration errors for both functions and classes.

Another way of preventing collisions between functions and classes is to use namespaces. We'll look at namespaces in my next article.


Bob Ray is the author of the MODX: The Official Guide and dozens of MODX Extras including QuickEmail, NewsPublisher, SiteCheck, GoRevo, Personalize, EZfaq, MyComponent and many more. His website is Bob’s Guides. It not only includes a plethora of MODX tutorials but there are some really great bread recipes there, as well.