Created
September 28, 2017 19:55
-
-
Save requinix/549f4166756820170d11a2f1001a89ac to your computer and use it in GitHub Desktop.
Global functions with (nearly) totally private shared data
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 | |
/* | |
Can I write global functions in PHP that share data between them, without also making that data | |
accessible to everyone else? | |
Global functions have a particular utility that is handy, even in an OOP codebase: it doesn't | |
require a fully-qualified class name/use statement and when in the root namespace the function will | |
be automatically resolved from any other namespace automatically (though prepending that slash is | |
hardly any effort). | |
Having one stand-alone function is fine but having two or more that need to share some data is a | |
bit harder. Obviously you can use a global variable, but then that variable is available to anyone | |
who wants to use it. | |
Javascript has its variable scope rules that make an easy solution to the problem. One used often. | |
(function() { | |
var _data = "..."; | |
function global_get() { return _data; } // window.global_get = function() { ... } | |
function global_set(value) { _data = value; } // window.global_set = function() { ... } | |
})(); | |
PHP doesn't have scope rules like that; anonymous functions can manually import variables from the | |
parent scope but regular functions cannot. Your choices are either | |
a) Leave the data global and tell people, at least with comments, not to mess with it, or | |
b) Forget the global functions and use a class with private instance/static variables. | |
Personally I would do the first one: I think it's reasonable to have other developers leave stuff | |
alone, and creating a class just for the sake of a private variable or two is annoying. So is there | |
a third option? | |
Ironically, my solution *does* use a class, but it's an anonymous class so it doesn't come with | |
the hassles of naming, allocating a file for the source, having the class source separate from the | |
global functions that use it, etc. | |
*/ | |
// class will have a generated name that's very difficult to guess | |
new class { | |
private static $data = "..."; | |
public function __construct() { | |
// conditionally-defined functions hoisted to global scope | |
// they can't use the run-time $this but they can use the compile-time __CLASS__ | |
function global_get() { return [__CLASS__, "get"](); } | |
function global_set($value) { [__CLASS__, "set"]($value); } | |
} | |
// public access, but good luck trying to call them from anywhere else | |
public static function get() { return self::$data; } | |
public static function set($value) { self::$data = $value; } | |
}; | |
global_set("foo"); | |
echo global_get(); | |
/* | |
It's short and simple enough that I'm satisfied with the implementation. Plus it looks fun. | |
Of course, as with any language that features reflection capabilities, the data isn't truly | |
private, but you have to work for it: get_declared_classes(), look for anonymous classes, and throw | |
in reflection to look for the right signature. | |
That said, I wouldn't use this a lot. My use case is a framework that allows one to "boot" a site | |
and then later "reboot" somewhere else; long story short the boot and reboot functions need to | |
safely share a common set of startup/shutdown handlers. | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment