PHP Nested Include Behavior

php nested include behavior

In cases when I need to use relative paths I use the following syntax:

include (realpath(dirname(__FILE__)."/another_folder/myfile.php"));

Nested include with PHP

assuming that the filesystem looks like this..

/www
include/header.php
class/Login.class.php
class/Connection.class.php
resources/login/index_alt.php
resources/login/index_auth.php
index.php

this means that

index.php: include(__DIR__ . '/include/header.php');
header.php: include(__DIR__ . '/../resources/login/index_alt.php');
index_alt.php: include(__DIR__ . '/index_auth.php');

etc; see http://php.net/manual/en/language.constants.predefined.php

Relative paths and nested includes

I had a similar challenge and created a single file that defines constants for all the relevant paths that I want to be able to call as-needed. I include this file in all my pages (I define the $urlRoot so that this will work in all environments and is moveable do different domains, etc):

File: pathData.php (added MENUDIR for your example):

$baseDir = dirname(__DIR__) . '/';
$rootUrl = (!empty($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . '/';
define('ROOTURL', $rootUrl);
define('BASEDIR', $baseDir);
define('INCLUDES', $baseDir . 'includes/');
define('INCLUDESURL', ROOTURL . 'includes/');
define('JQUERYURL', ROOTURL . 'includes/jquery/');
define('MENUDIR', ROOTURL . 'views/general/');

Then in each file, I include that file with an include that includes the relative directory path. For example:

include("pathData.php");
or
include("../pathData.php");
or
include("../../pathData.php);
etc.

So in your case you could (depending on where your pathData file is):

include("../pathData.php");
include(MENUDIR . "navbar.php");
etc...

Prevent including the same file during nested include

The include_once() statement includes and evaluates the specified file during the execution of the script. This is a behavior similar to the include() statement, with the only difference being that if the code from a file has already been included, it will not be included again. As the name suggests, it will be included just once.

Ref: include_once()

Why does PHP Include not work with child Includes?

I think multiple includes doesn't cause problems ... but if it doesn't work for you, it's most probably you have a conflict in the files' paths.

My advice is to test the includes statements one by one for example:-

include 'tabs.php';

if the above line works fine, add into "tabs.php" the following line

include 'tab-1.php' 

and keep going until you find the file where the problem happens.

Nested php includes using './'

No. Using ./ at the start of your include file name forces it to be searched from the "current directory" as set by your web server (most probably the directory of the initial script, or the DocumentRoot, depending on the webserver).

The way to get the behaviour you want depends on the value of your include_path (which can be modified with set_include_path() if necessary).

From the documentation for include():

Files for including are first looked for in each include_path entry relative to the current working directory, and then in the directory of current script. E.g. if your include_path is libraries, current working directory is /www/, you included include/a.php and there is include "b.php" in that file, b.php is first looked in /www/libraries/ and then in /www/include/. If filename begins with ./ or ../, it is looked for only in the current working directory or parent of the current working directory, respectively.

So, if there's no chance that the filename will be found in another directory in the include_path first, you could use include('apple.php').

If there is a possibility that apple.php exists elsewhere, and you want the copy in this folder to be used first, you could either use Matthew's suggestion, and

include(dirname(__FILE__).'/apple.php');

or, if you have many files to include from the current directory:

old_include_path = set_include_path(dirname(__FILE__));
include('apple.php');
include('orange.php');
include('peach.php');
include('pear.php');
set_include_path(old_include_path);

PHP: How to change search behaviour of include/require function?

But is it possible to implement the reverse behaviour: first of all look at current dir, and after that into dir in include_path variable?

Make the current dir the first one in the list of directories this setting contains.

http://php.net/manual/en/ini.core.php#ini.include-path:

Using a . in the include path allows for relative includes as it means the current directory.

The default value for this setting is .;/path/to/php/pear, so that would search the current directory first already. (On a unix system, the separator is : instead of ;)

If you need this on systems where you don’t know the configuration up-front, check if the first entry is a ., and if not, add it. (You might want to make sure it doesn’t occur again later in the list, so as to not have the same directory searched twice.)

get_include_path and set_include_path can be used, or ini_get and ini_set.

Nested or Inner Class in PHP

Intro:

Nested classes relate to other classes a little differently than outer classes. Taking Java as an example:

Non-static nested classes have access to other members of the enclosing class, even if they are declared private. Also, non-static nested classes require an instance of the parent class to be instantiated.

OuterClass outerObj = new OuterClass(arguments);
outerObj.InnerClass innerObj = outerObj.new InnerClass(arguments);

There are several compelling reasons for using them:

  • It is a way of logically grouping classes that are only used in one place.

If a class is useful to only one other class, then it is logical to
relate and embed it in that class and keep the two together.

  • It increases encapsulation.

Consider two top-level classes, A and B, where B needs access to
members of A that would otherwise be declared private. By hiding class
B within class A, A's members can be declared private and B can access
them. In addition, B itself can be hidden from the outside world.

  • Nested classes can lead to more readable and maintainable code.

A nested class usually relates to it's parent class and together form a "package"

In PHP

You can have similar behavior in PHP without nested classes.

If all you want to achieve is structure/organization, as Package.OuterClass.InnerClass, PHP namespaces might sufice. You can even declare more than one namespace in the same file (although, due to standard autoloading features, that might not be advisable).

namespace;
class OuterClass {}

namespace OuterClass;
class InnerClass {}

If you desire to emulate other characteristics, such as member visibility, it takes a little more effort.

Defining the "package" class

namespace {

class Package {

/* protect constructor so that objects can't be instantiated from outside
* Since all classes inherit from Package class, they can instantiate eachother
* simulating protected InnerClasses
*/
protected function __construct() {}

/* This magic method is called everytime an inaccessible method is called
* (either by visibility contrains or it doesn't exist)
* Here we are simulating shared protected methods across "package" classes
* This method is inherited by all child classes of Package
*/
public function __call($method, $args) {

//class name
$class = get_class($this);

/* we check if a method exists, if not we throw an exception
* similar to the default error
*/
if (method_exists($this, $method)) {

/* The method exists so now we want to know if the
* caller is a child of our Package class. If not we throw an exception
* Note: This is a kind of a dirty way of finding out who's
* calling the method by using debug_backtrace and reflection
*/
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
if (isset($trace[2])) {
$ref = new ReflectionClass($trace[2]['class']);
if ($ref->isSubclassOf(__CLASS__)) {
return $this->$method($args);
}
}
throw new \Exception("Call to private method $class::$method()");
} else {
throw new \Exception("Call to undefined method $class::$method()");
}
}
}
}

Use case

namespace Package {
class MyParent extends \Package {
public $publicChild;
protected $protectedChild;

public function __construct() {
//instantiate public child inside parent
$this->publicChild = new \Package\MyParent\PublicChild();
//instantiate protected child inside parent
$this->protectedChild = new \Package\MyParent\ProtectedChild();
}

public function test() {
echo "Call from parent -> ";
$this->publicChild->protectedMethod();
$this->protectedChild->protectedMethod();

echo "<br>Siblings<br>";
$this->publicChild->callSibling($this->protectedChild);
}
}
}

namespace Package\MyParent
{
class PublicChild extends \Package {
//Makes the constructor public, hence callable from outside
public function __construct() {}
protected function protectedMethod() {
echo "I'm ".get_class($this)." protected method<br>";
}

protected function callSibling($sibling) {
echo "Call from " . get_class($this) . " -> ";
$sibling->protectedMethod();
}
}
class ProtectedChild extends \Package {
protected function protectedMethod() {
echo "I'm ".get_class($this)." protected method<br>";
}

protected function callSibling($sibling) {
echo "Call from " . get_class($this) . " -> ";
$sibling->protectedMethod();
}
}
}

Testing

$parent = new Package\MyParent();
$parent->test();
$pubChild = new Package\MyParent\PublicChild();//create new public child (possible)
$protChild = new Package\MyParent\ProtectedChild(); //create new protected child (ERROR)

Output:

Call from parent -> I'm Package protected method
I'm Package protected method

Siblings
Call from Package -> I'm Package protected method
Fatal error: Call to protected Package::__construct() from invalid context

NOTE:

I really don't think trying to emulate innerClasses in PHP is such a good idea. I think the code is less clean and readable. Also, there are probably other ways to achieve similar results using a well established pattern such as the Observer, Decorator ou COmposition Pattern. Sometimes, even simple inheritance is sufficient.



Related Topics



Leave a reply



Submit