Last active
December 20, 2015 23:39
-
-
Save jtickle/6213838 to your computer and use it in GitHub Desktop.
Functional PHP: A getModule function that works like Node.js' require()
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// I have no idea how to solve the problem of the fact that anything | |
// declared here ends up on the global scope. Namespaces, maybe? But | |
// I'm doing this in part to get away from namespaces and just let things | |
// be functional. So I wrap it up in this load function but you should | |
// try to pick some name that won't conflict. | |
function fancyApi(&$exports) { | |
$myConfig = 'World'; | |
// This fancy API simply prints a familiar message given the right inputs | |
$exports['sayHello'] = function($hello) use ($myConfig) { | |
echo "$hello, $myConfig!\n"; | |
}; | |
} | |
fancyApi($exports); | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// This feels dirty | |
define('DS', '/'); | |
// We have to initialize it with configuration. Your software could just | |
// declare getModule as a non-anonymous function if you really wanted. | |
function createGetModule($basePath) { | |
// We will store our loaded modules here. Each call to createGetModule | |
// gets its own module cache. It's Functional Programming, and that's | |
// how it goes. | |
$loaded = array(); | |
// Return the actual getModule function | |
return function($path) use ($loaded, $basePath) { | |
// If a load hasn't happened before, we need to go do the actual load. | |
if(!array_key_exists($path, $loaded)) { | |
// Build the path - this could be configurable with more stuff passed | |
// into the outer function createGetModule | |
$file = $basePath . DS . $path . '.php'; | |
// Sanity checking because I like Exceptions better than Errors | |
if(!file_exists($file)) throw new Exception($file . ' does not exist.'); | |
// The module just expects that this array will be available to it. | |
// Everything the module exports will be put onto $exports. | |
$exports = array(); | |
// Load the module in the PHP way | |
require $file; | |
// Cache the results. Modules are singletons. | |
$loaded[$path] = $exports; | |
} | |
// Return the result from cache | |
return $loaded[$path]; | |
}; | |
} | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/php | |
<?php | |
// We have to bootstrap things the old-fashioned way | |
require('getModule.php'); | |
// Assign the getModule behavior to a variable. Note that createGetModule returns a function. | |
$getModule = createGetModule(__DIR__); | |
// Use getModule to load fancyApi's exports | |
$api = $getModule('fancyApi'); | |
echo "Here is what we get back:\n"; | |
var_dump($api); | |
echo "\n\nAnd here is what happens if we run it:\n"; | |
$api['sayHello']('Hello'); | |
echo "\nUnfortunately, that function declared in fancyApi.php polluted the global scope:\nis_callable('fancyApi') = "; | |
var_dump(is_callable('fancyApi')); | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment