3

So I had this idea to map my framework's folder structure to namespaces with a dynamic build process.

To give you an idea how this would work here an example structure:

src/
    FS/
       File/
            open.php (function)
    Math/
         add.php (function)
         test.php (function)
         MAGIC.php (constant)

Would be translated to:

namespace FS\File {
    function open() { /* ... */ }
}

namespace Math {
    function add() { /* ... */ }
    function test() { /* ... */ }
    const MAGIC = /* ... */;
}

There would be no support for classes.

A function would be defined as follows:

<?php
/**
 * src/Math/add.php
 *
 * This is the Math\add module.
 */
return function($require) {
    // Require Math\test module.
    $test = $require('Math\test');

    return function($a, $b) use ($test) {
        // Call Math\test function
        $test($a, $b);

        return $a + $b;
    };
};
?>

The outer most function is for providing a new scope (so all previous defined variables are non existing).

Then the $require variable is for including other modules.

(The idea to require all other dependencies came from node. I think this would make mocking and testing a lot easier because one could test the module with an overwritten $require variable.)

And constants could be defined as follows:

<?php
/**
 * src/Math/MAGIC.php
 */
return 0xDEADBEEF;
?>

The whole framework would then have a require method to load a module from filesystem:

/**
 * Function that is responsible to load a module.
 */
function require($module) {
    static $loadedModules = [];

    $modFileName = str_replace('\\', '/', $module);

    // Check if already loaded or load from file system
    // ...
    // ...

    return $loadedModule;
}

So using Math\add would look like this:

require('Math\add')('require')(1, 2)
                   // ^- dependency loader function

Of course this does not look very nice so the build process would generate the namespaces and automatically fill in the require calls:

namespace Math {
    function add(...$args) {
        return require(__FUNCTION__)('require')(...$args);
    }

    /* Or constants ... */
    const MAGIC = 0xDEADBEEF;
}

Constants could be require'd in the same fashion as functions:

require('Math\MAGIC') // 0xDEADBEEF
// or through the generated namespace
Math\MAGIC // 0xDEADBEEF

The benefits I see:

  • Flexible structure (namespaces are generated automatically).
  • Easily mockable and testable.
  • Clear dependencies (dependencies are always require'd)

But I can also see the danger of having too many variables because of the way dependencies are managed. Also I'm not too sure about the performance.

I have never seen such an architecture and I'm curious what others think of my concept.

5
  • Also worth noting: I've made a proof of concept so this is actually possible. I can put it on GitHub if anyone is interested to see my implementation.
    – Marco
    Jan 12, 2017 at 22:29
  • Looks like you always have to write a lot of additional code, every one function call turns into three (if I counted correctly) and if I understand PHP correctly, every function call allocates new memory.
    – Jimmy T.
    Jan 15, 2017 at 17:12
  • 1
    In theory it seems feasible. I'm not sure what benefit you have by having a build process define the structure for you though. Why not define it all as you need it from the start and skip then build?
    – scrowler
    Jan 15, 2017 at 19:02
  • @JimmyT. Yep, that's what I observed with blackfire.io as well.
    – Marco
    Jan 16, 2017 at 12:24
  • 1
    require is a reserved word in PHP.
    – Mike Brant
    Jan 18, 2017 at 19:51

1 Answer 1

-1

It is hard to tell would it have any advantages at all. Probably the best thing is to make small project to see what are advantages/disadvantages using this method of code organization.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.