In my Beyond Frameworks talk, I explained how a component-based architecture can help answer some of the important (i.e. expensive!) questions you might face when creating long-lived apps that rely on a PHP framework. In this series of blog posts, I’m going to look at how to go about creating and working with components.

A component-based approach works well with the new namespace support added to PHP 5.3, and indeed I’m making full use of this in the components I’m building for this tutorial. But not everyone is ready to move to namespaces, and when you start to consume older components inside yours, you might run into errors.

Namespaces Recapped

The whole idea behind namespaces is to make life easier for developers, by doing away with having to type incredibly long class names all the time. For example, take the ConsoleDisplayLib component I recently released. In the pre-PHP 5.3 days, I would have had to define the classes it provides like this:

[code lang=”php”]
class Phix_Project_ConsoleDisplayLib_StdOut { … }
[/code]

… and then when I wanted to use it, I would have to do this:

[code lang=”php”]
$stdout = new Phix_Project_ConsoleDisplayLib_StdOut();
[/code]

A workable system, to be sure, and one that OO PHP programmers have used for many years, but hardly RSI-friendly, I’m sure you agree. With namespaces, however, things change. The class is now defined like this:

[code lang=”php”]
class Phix_ProjectConsoleDisplayLibStdOut { … }
[/code]

Note the use of ” instead of underscores. That’s PHP’s new namespace separator, and it tells PHP that the class StdOut lives inside the Phix_ProjectConsoleDisplayLib namespace, which in turn lives inside the Phix_Project namespace. Namespaces are just another kind of scope, like local scope vs global scope. Hold that thought, because it’s these new scopes that affect our attempts to mix in non-namespaced code.

If I’m writing code that is part of ConsoleDisplayLib, to create a new StdOut object, I now only need to do this:

[code lang=”php”]
namespace Phix_ProjectConsoleDisplayLib;

$stdout = new StdOut();
[/code]

PHP automatically expands ‘StdOut’ to mean ‘Phix_ProjectConsoleDisplayLibStdOut’, because I’ve used the namespace keyword to tell PHP that this code is part of Phix_ProjectConsoleDisplayLib.

And that is where the fun begins.

Adding HTTP_Request2 To RepustateApi

I’ve made the choice to reuse the existing PEAR component HTTP_Request2. The PEAR project doesn’t currently use namespaces; all classes defined by HTTP_Request2 exist in the global scope. So if I try to use HTTP_Request2 like this inside my Repustate API client:

[code lang=”php”]
namespace GradwellRepustateApi;

$httpClient = new HTTP_Request2($url, HTTP_Request2::METHOD_POST);
[/code]

… PHP reports the fatal error: Class GradwellRepustateApiHTTP_Request2 not found.

First time you see this, you might be wondering what is going on, and how to fix it. After all, the class is called HTTP_Request2. Why is PHP trying to load a class called GradwellRepustateApiHTTP_Request2?

The answer is simple. By using the namespace keyword at the top of the file, I’ve told PHP to assume that all of the code in this file is part of the GradwellRepustateAPI scope. So, just like in my ConsoleDisplayLib example where PHP automatically expanded StdOut to be Phix_ProjectConsoleDisplayLibStdOut, PHP is going to expand HTTP_Request2 to be GradwellRepustateApiHTTP_Request2.

That isn’t what we want, but that’s PHP’s fault. We need to tell PHP that, in this case, we want it to load HTTP_Request2, and not GradwellRepustateApiHTTP_Request2.

Load From The Global Namespace

Getting PHP to load code from the global namespace, instead of from your component’s namespace, is very easy … you’ve just got to remember to do it everywhere. Simply make sure you’ve put a ” at the start of any classnames that are part of the global namespace:

[code lang=”php”]
namespace GradwellRepustateApi;

$httpClient = new HTTP_Request2($url, HTTP_Request2::METHOD_POST);
[/code]

Remember to do this, and you’ll have no trouble working with non-namespaced components inside your own components.

No Comments

  1. Richy C. says:
    October 26th, 2011 at 10:38 am

    Hi Stuart,

    I did ask this over Twitter, but 140 characters aren’t long enough to convey the question I had.

    Basically, I would like my multiple packages created by Phix to be namespaced under a common “organisation name”: i.e.

    richyc/package_a
    richyc/package_b

    with files such as
    richyc/package_c/monkey/island.php being
    ===================
    namespace richycpackage_cmonkey
    class island {
    ==================

    This is to avoid clashes (for example, my autoloader vs yours).

    What would be the best name to put in project.name in the build.properties and the ideal layout of the code (I have src/php/richyc/package_c/monkey/island.php )?

    I’ve got it compiling PEAR modules, but it’s just refining it at the moment. Any advice welcome! ;)

  2. Richy C. says:
    October 26th, 2011 at 10:38 am

    Hi Stuart,

    I did ask this over Twitter, but 140 characters aren’t long enough to convey the question I had.

    Basically, I would like my multiple packages created by Phix to be namespaced under a common “organisation name”: i.e.

    richyc/package_a
    richyc/package_b

    with files such as
    richyc/package_c/monkey/island.php being
    ===================
    namespace richycpackage_cmonkey
    class island {
    ==================

    This is to avoid clashes (for example, my autoloader vs yours).

    What would be the best name to put in project.name in the build.properties and the ideal layout of the code (I have src/php/richyc/package_c/monkey/island.php )?

    I’ve got it compiling PEAR modules, but it’s just refining it at the moment. Any advice welcome! ;)

  3. Stuart Herbert says:
    October 26th, 2011 at 12:23 pm

    Hi Rich,

    I would recommend setting project.name to be ‘package_a’ or ‘package_b’ as appropriate. The layout you’ve suggested looks like what I would do in the same circumstances.

    Hope that helps,
    Stu!

  4. Stuart Herbert says:
    October 26th, 2011 at 12:23 pm

    Hi Rich,

    I would recommend setting project.name to be ‘package_a’ or ‘package_b’ as appropriate. The layout you’ve suggested looks like what I would do in the same circumstances.

    Hope that helps,
    Stu!

  5. Richy C. says:
    October 28th, 2011 at 12:43 pm

    So I’ll need to use something like:
    include “package_a/richyc/package_a/file.php”
    and “autoload” things such as:
    package_a/richyc/package_a
    or am I missing something?

    I expected to be able to make a namespaced package so that I could just called them as “richyc/package_a/file.php”.

    In otherwords, you’ve got a “hexdump” extension. I might make my own, but they both need to be installed on the same system. Someone might want to use “stuherbert/hexdump” and also “richyc/hexdump”. However, if we both call ours “hexdump”, we’re going to get clashes in PEAR…

  6. Richy C. says:
    October 28th, 2011 at 12:43 pm

    So I’ll need to use something like:
    include “package_a/richyc/package_a/file.php”
    and “autoload” things such as:
    package_a/richyc/package_a
    or am I missing something?

    I expected to be able to make a namespaced package so that I could just called them as “richyc/package_a/file.php”.

    In otherwords, you’ve got a “hexdump” extension. I might make my own, but they both need to be installed on the same system. Someone might want to use “stuherbert/hexdump” and also “richyc/hexdump”. However, if we both call ours “hexdump”, we’re going to get clashes in PEAR…

This Month

March 2011
M T W T F S S
« Feb   Apr »
 123456
78910111213
14151617181920
21222324252627
28293031