Update: I evidently simplified the issue too much, and have had several
people rightly comment on the bogosity of the issue. However, there are still situations
where $GLOBALS does not act as expected, and I outline these in
my next entry.
In my previous
entry, I ranted about the use of globals in popular PHP
applications, and how they make embedding said applications difficult. I
develop using object-oriented practices, and can honestly say I can't recall
ever having slung a global variable around in my own code. Globals seem
hackish to me, and as a result, trying to get applications that use them
to behave correctly has been a challenge.
One of the applications I had in mind was Serendipity, the software that powers this
blog. I was attempting to create a Zend Framework action controller that
wraps my s9y instance so that I can do things such as apply ACLs from my
website to selected entries, as well as pull the sitewide skeleton out from
s9y so that I only have to maintain one version of it (I had one version for
s9y, and another for my own content featured on the site (resume, contact
form, etc.).
I tried importing the various config files into my action method prior to
invoking the actual s9y bootstrap, but no dice. I also tried modifying the
s9y config files to use the notation $GLOBALS['serendipity']
around the serendipity configuration variables (s9y uses a single
multi-dimensional array for all configuration options). This didn't work,
either; s9y functions that called global $serendipity were still
getting a null value.
So, I did a little closer reading in the manual section on
predefined variables, I discovered something interesting in the
description of $GLOBALS (emphasis mine):
Contains a reference to every variable which is currently available
within the global scope of the script.
Interestingly, the section on variable scope didn't make this distinction at
all. Basically, if the variable you reference via $GLOBALS does
not already exist, assigning it does nothing. It doesn't even raise
a notice. It just silently goes ahead, leaving you thinking you set a new
global variable, but in fact, you cannot assign new globals via
$GLOBALS; you can only modify existing variables in the
global scope.
So, I got around the issue by putting this in my front controller bootstrap:
$serendipity = null;
After that, I was able to create a wrapper action controller for s9y very
easily:
/** Zend_Controller_Action */require_once 'Zend/Controller/Action.php';
/**
* Serendipity integration
*
* @uses Zend_Controller_Action
*/class S9y_IndexController extends Zend_Controller_Action
{ public
function init
() { // New ViewRenderer helper in ZF incubator; telling it not // to autorender a view script when done $this->_helper->
viewRenderer->
initView(null,
null,
array('noRender' =>
true));
} public
function indexAction
() { global $serendipity;
chdir($_SERVER['DOCUMENT_ROOT'] .
'/path/to/s9y');
include './index.php';
chdir($_SERVER['DOCUMENT_ROOT']);
}}
Note that I don't do any output buffering; this is because the ZF dispatcher
takes care of that for me. All I need to do is execute the s9y bootstrap.
So, the lesson to learn from all this: if you need to wrap an application
that uses globals, find out what all of them are, and declare them in the
global namespace -- just setting them to null is enough -- in your
application bootstrap.