Skip to content

Instantly share code, notes, and snippets.

@requinix
Created September 28, 2017 19:55
Show Gist options
  • Save requinix/549f4166756820170d11a2f1001a89ac to your computer and use it in GitHub Desktop.
Save requinix/549f4166756820170d11a2f1001a89ac to your computer and use it in GitHub Desktop.
Global functions with (nearly) totally private shared data
<?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