Skip to content

Instantly share code, notes, and snippets.

@a904guy
Last active December 19, 2015 19:29
Show Gist options
  • Save a904guy/6006941 to your computer and use it in GitHub Desktop.
Save a904guy/6006941 to your computer and use it in GitHub Desktop.
Singleton Constructor that makes Functions based on Class names for easy access in PHP. Include it before an SPL autoloader, and you've got a shorthand method to creating class instances.IE: class db can be called like so: db(construction_vars)->method(vars)
<?php
/*
Author: Andy Hawkins
Email: YW5keUBhOTA0Z3V5LmNvbQ==
Facebook: http://fb.me/andyhawkins
HackerNews: http://hackerne.ws/user?id=a904guy
This file will allow you to create a project that will create global functions that allow you to instantly access and singleton classes from their class name
In the variables below I've defined a project folder called '/myproject/', and inside that folder there is an 'obj/' folder which contains your classes:
/myproject/obj/
db.class.php
cache.class.php
Once this code is executed, you can then call either easily from your code like so:
db()->set_creds('l33t','h@#0r');
if(is_null($data = cache()->get("mysqlquery")))
{
$data = db()->query("Select...");
cache()->set("mysqlquery",$data);
}
var_dump($data);
etc.
You can even pass constructor variables to these functions to create the singletons, they are keep separately, so no two returned methods with parameters defined collide.
db('mysql')
db('sqlite')
Will return their respective classes initialized using the supplied variables.
*/
// Configuration
$_CODE = array(); // Used to store object instances created.
$_CODE['code_pwd'] = '/myproject/';
$_CODE['objs_pwd'] = 'obj/';
/*
getPath ensures that the path given cannot break from the chroot path inside $_CODE['code_pwd'] or it will return false;
I would recommend using this in any project so that if you have to use variables within an include (dear jebus, DON'T!)
it will atleast make sure they are chrooted to your project path
*/
function getPath($path='')
{
global $_CODE;
$path = str_replace('//','/',$path);
$test = strpos(realpath($_CODE['code_pwd'].$path),rtrim($_CODE['code_pwd'],'/'));
if(is_numeric($test) and $test === 0)
{
return $_CODE['code_pwd'].$path;
}else{
return false;
}
return false;
}
/*
The singleton class will scan the folder in question looking for files ending in .class.php, it will then create a function using the file/class name that can be called anywhere. I'll be burned alive for implementing "eval", but I assure you there is no way to exploit it. If you a wizard and do so, please email me, and I'll buy you a beer.
It will not actually read the contents of the files for the sake of speed, so Naming convention has to match the filename db = db.class.php (This can be changed below easily).
Although you can make class revisions easily without breaking your code by specifying in db.class.php that class_alias('db_v2','db') and call the new class by using db() still.
NOTE: I haven't used this to work with namespaces yet, but it could easily be done so with a folder, and file naming convention logic.
*/
final class singleton // Create singleton functions for each global object. Bit of a hack, but a sweet sweet juicy hack.
{
function __construct()
{
$path = getPath($_CODE['objs_pwd']);
foreach(explode("\n",trim(`find {$path}* -type f`)) as $file)
{
$name = str_replace(array('.class.php',$path),'',$file);
if(!function_exists($name)) eval("function {$name}() { \$vars = array_values(func_get_args()); return (count(\$vars) > 0) ? o(__FUNCTION__,\$vars) : o(__FUNCTION__); }");
}
}
}
// Factory Function o called from dynamically created Functions initialized in the Singleton Class to return the object.
// This function also handles keep track of the previously initialized objects and return them as needed.
function o($obj) // Object Overloader, Singleton Factory
{
global $_CODE;
$vars = func_get_args();
$obj = array_shift($vars);
$tmp = func_get_args();
$key_data = array_pop($tmp);
$key = crc32(@json_encode($key_data).$obj);
$vars = func_clean_args($vars);
if(array_key_exists($key,$_CODE['obj'])) return $_CODE['obj'][$key];
// Magic
if(class_exists($obj)) {
$class = new ReflectionClass($obj);
if($class->hasMethod('__construct')) // php5.3 hack until we move onto 5.4 and newInstanceWithoutConstructor is available
{
$_CODE['obj'][$key] = $class->newInstanceArgs($vars);
}else{
$_CODE['obj'][$key] = $class->newInstance();
}
return $_CODE['obj'][$key];
}
return null; // For attempted access to chrooted objects happen
}
// Simple function to rearrange the func_get_args, to work with ReflectionClass::newInstanceArgs()
// This could be turned into a map but what the hell it works great and is fast;
function func_clean_args($arr)
{
$return = array();
foreach($arr as $k) {foreach($k as $v) { $return[] = $v; }}
return $return;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment