How do we keep the namespace clean with multiple PHP files?

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
BlindMan
Forum Newbie
Posts: 7
Joined: Fri Dec 16, 2005 11:21 pm

How do we keep the namespace clean with multiple PHP files?

Post by BlindMan »

PHP seems to have serious namespace issues when scripts are broken into multiple files. For instance, if I have an HTML file that needs to run functions or read variables from a PHP file, I can’t treat the PHP file as a class with member functions/variables. I have to run the PHP files and then make assumptions about the names of the functions/variables (as globals). What’s more, PHP doesn’t seem to object if globals are overwritten by other PHP files.

Am I missing something here (I'm very newbie)?
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

If I read that right.. you are saving a class (for example MyClass) in the file MyClass.php then trying to call the class without including it? ala Java - PHP does not do this, you must use require/include functions to use the file (and it's contents as PHP script)

And are you also using the Variable Scope incorrectly?

PHP is a scripting language that has aspects of OOP. You must "gather" all the relevant bits of PHP script that you need as at run time to form a big script in memory. So all your class definitions, function definitions etc. need to be included before you can use them.

As for the globals problem.. well, using global $var; in a class can be problematic if you are not careful with the naming of said variables/properties. An example for a weak name:

Code: Select all

class MyClass
{
    function MyClass ()
    {
        global $result; // contains .. oh I dunno, a setting for the format of a result.
        //do something with $result;
    }
}

$result = mysql_query("SELECT * FROM `table`");

MyClass::MyClass(); //error - $result no longer contains the value of the setting.
A better example:

Code: Select all

class MyClass
{
    function MyClass ()
    {
        global $MyClassResultFormat; // contains .. oh I dunno, a setting for the format of a result.
        //do something with $MyClassResultFormat;
    }
}

$result = mysql_query("SELECT * FROM `table`");

MyClass::MyClass(); //no error - $MyClassResultFormat is not likely to be used by coincidence.
or even better, use a constant so that even if done by coincidence, you or future developers will know immediately by means of a "constant already defined" error.

Sorry if this is not what you refer to.. I don't fully understand what you mean.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: How do we keep the namespace clean with multiple PHP fil

Post by Chris Corbyn »

Just to back Jenk up since I read what you've said the same way Jenk has.
BlindMan wrote:PHP seems to have serious namespace issues when scripts are broken into multiple files. For instance, if I have an HTML file that needs to run functions or read variables from a PHP file, I can’t treat the PHP file as a class with member functions/variables. I have to run the PHP files and then make assumptions about the names of the functions/variables (as globals).
This is how PHP works yes... it's not like C or Java, the contents of the files are pulled into the scripts inline.
BlindMan wrote:What’s more, PHP doesn’t seem to object if globals are overwritten by other PHP files.

Am I missing something here (I'm very newbie)?
Correct, that's why it's *usually* ideal to minimize globals as much as possible by factorising into many classes etc. As Jenk says, constants will error if you try to overwrite. You can use define() for globally accessible constants, or the "const" keyword for static constants in PHP5 OOP.

If you really want to prevent overriding your globals you can always do some checking before you assign values to them too.
BlindMan
Forum Newbie
Posts: 7
Joined: Fri Dec 16, 2005 11:21 pm

Post by BlindMan »

I believe I found a solution, but first let me clarify the problem...

I do understand that files are run in-line and that's how you get data/function definitions from other files.

The problem is that the code in one file must make assumptions about the names of variables/functions in order to use code in other files, and I thought that these assumptions applied to the global namespace. In the example provided, “MyClassResultFormat” is a good name because it ‘seems unique enough’ to prevent a namespace collision. I dislike situations like this where there’s nothing to protect us but convention—especially when global variables can be overwritten by subsequently included PHP files.

Solution...?

If we include a PHP file from within the scope of a function, and the variables within the file are not “global”, these variable will not affect any of the global variables of our main file (protects our global namespace).

For Example...

Code: Select all

<!-- File: PersonIndex.html -->
<?php
    $person = new Person("foo");
    
    // if we wrap the 'include' with a function, we prevent the included file
    // from affecting the global variables ('$person')
    function LoadPerson1()
    {
        include("Person1.php");
        return $person;
    }
    function LoadPerson2()
    {
        include("Person2.php");
        return $person;
    }
    
    $person1 = LoadPerson1();
    $person2 = LoadPerson2();
    
    // $person is still "foo"
?>

<!-- File: Person1.html -->
<?php
    $person = new Person("one");
?>

<!-- File: Person2.html -->
<?php
    $person = new Person("two");
?>
Given this solution, it seems that PHP files should interface with each other through variables, not functions, when possible. Function names have only one, global namespace.
Last edited by BlindMan on Sun Dec 18, 2005 5:35 pm, edited 1 time in total.
BlindMan
Forum Newbie
Posts: 7
Joined: Fri Dec 16, 2005 11:21 pm

Post by BlindMan »

BTW, thanks for the feedback guys. :D
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Post by Maugrim_The_Reaper »

IMO - not sure what the above was intended to accomplish (besides confusing me ;)). The repitition in your script suggests there's a better solution... But hey, if it works...:)
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

In your given example, the seperation of files is not necessary, it can be condensed to:

Code: Select all

<?php

$person = new Person("foo");
$person1 = new Person("one");
$person2 = new Person("two");

?>
I know it's only an example, but maybe this is an indication of where you might be doing things wrong and not need to execute the instantiation of an object in a serperate file like that.

(also, a pedantic and worthless point, you have include("person1/2.php"); but have <!-- File person1/2.html --> :p)

BTW, this next suggestion I am not sure about, but try returning $person by reference, I know PHP now does this "by default" but it's worth a try..

Code: Select all

<?php

function & LoadPerson1 () {
    include("person1.php");
    return $person;
}

$person1 =& LoadPerson1();
?>
It's also probably not a good idea to contain class definitions or object instantiations inside a function. Don't quote me on it though.
Post Reply