PhpLanguage has many odd language features which end up introducing odd namespaces and global state couplings. This is a topic I've been thinking about for some time, and what I'd like to evolve here is strategies or mini-patterns or idioms for maintaining orthogonality in PHP.
Use of autoglobals:
PHP has $_REQUEST[], $_POST[], $_GET[], $_SERVER[] and $_SESSION[] autoglobals.
- They are effectively global variables.
- Using them sprinkled throughout code couples components with the program's global state
To maintain orthogonality:
First strategy (make unglobal):
- Copy values to a local variable.
- If paranoid, unset the autoglobal (except $_SESSION).
- Pass local reference to methods which need it.
Second strategy (encapsulate with local object):
- Construct a request object from autoglobals, store in local variable
- If paranoid, unset autoglobals (except $_SESSION)
- Dispatch request to handler method/object/file
Third strategy (define where to access):
- Do not reference these except from top-level scripts (ones directly called by web server).
In other words, top-level .php scripts are
ModelViewController controllers.
Program output:
PHP has:
- ob_start(), ob_end(), ob_end_clear(), etc.
- Methods such as 'printf' and 'echo' and 'print' which output to the current context.
It may be thought of in this way: PHP has two methods for returning textual data. Via "return" and via "echo." Using "echo" can be caught using ob_start(), ob_end().
To maintain orthogonality:
- Components and methods should return their output, not echo it (except for a centralized location which outputs a request)
Alternately:
- Have an object which handles outputting and pass reference to all procedures which create output.
Regarding autoglobals:
You are welcome to wrap them behind functions or objects, but I've never encountered problems with these being global. If you have seen specific problems with it, I would like to study the scenarios. KISS wins out I think. Layers and layers of stuff "just in case" can make for verbose, hard-to-read code. (PrematureAbstraction). Generally if you have something fairly complicated to track the state of, the "PHP way" is to put it in the database. Loading up the SESSION array with lots of stuff is a smell in my opinion.
Let me relate the experiences that have caused me to conclude this:
- Trying to reuse a ModelViewController-type model in a CLI script, and getting warnings because something like "$foo->accessible()" depends on $_REQUEST['module']
- Writing unit tests for a model, and having a developer later introduce if ($_REQUEST['module'] == 'Foo') ..., causing the test to fail.
- Trying to write unit and functional tests for existing code, and finding it difficult to fudge the request because the behavior of miscellaneous utility functions and methods changes depending on session variables that I can't predict exist. Causing:
- Tests to fail when the production environment works
- Even worse, the test passes and it works in production sometimes. (SometimesItMakesThisNoise)
I've just added two more strategies. I'd be interested to read your comments.
I guess I am not a believer in ModelViewController. That may be the difference.
CategoryPhp