LogoPhly, boy, phly
the weblog and site of Matthew Weier O'Phinney

Saturday, May 19. 2007

PHP globals for the OOP developer

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.

Posted by Matthew Weier O'Phinney in PHP at 09:42 | Comments (9) | Trackback (1)

Trackbacks
Trackback specific URI for this entry

web design original
Great site and well thought out.Thanks
Weblog: web design original
Tracked: Jul 14, 13:43

Comments
Display comments as (Linear | Threaded)

I'm probably reading your dilemma incorrectly, but I get different results:

// $undefined is not defined

function assignToUndefined() {
global $undefined;
$undefined = true;
}

assignToUndefined();
var_dump($undefined); // true

And besides the point, you're exactly right: the application should be declaring all its globals itself.
#1 Edward Z. Yang (Link) on 2007-05-19 11:41 (Reply)
Hey Edward,

I think Matthew was talking about doing it like this:



The result:

Notice: Undefined variable: undefined in /home/jeremy/www/undefined.php on line 10
NULL
#1.1 Jeremy Privett (Link) on 2007-05-19 12:12 (Reply)
Stupid PHP tags... That code should've been:

// $undefined is not defined

function assignToUndefined()
{
$GLOBALS["undefined"] = "Whee?";
}

var_dump($undefined);
#1.1.1 Jeremy Privett (Link) on 2007-05-19 12:13 (Reply)
I can't reproduce the problem. This script works fine for me:

function setGlobal($name, $value) {
$GLOBALS[$name] = $value;
}
setGlobal('foo', 'bar');
var_dump($foo);
#2 Stephan Schmidt (Link) on 2007-05-19 12:09 (Reply)
That's interesting. Apparently, it only works if you're actually passing the value into the function.
#2.1 Jeremy Privett (Link) on 2007-05-19 12:17 (Reply)
Wow, I just made myself look like a big idiot. Bug in my above code, forgot to call the function. *dolp!*

Note to self, don't try doing this stuff immediately after waking up. :-P

All in all, I can't reproduce the problem either, now that I'm actually running the function.
#3 Jeremy Privett (Link) on 2007-05-19 12:19 (Reply)
I'll back up the claims to bogosity with a note that the $GLOBALS array isn't constructed as individual references to the global variables (i.e. $GLOBALS['foo'] =& $foo, $GLOBALS['bar'] = $bar, etc....) Rather $GLOBALS is itself a reference to the internal notion of the global symbol table. Ergo assigning values to heretofore undefined variables works, by design.

Whatever caused you to experience otherwise was based on something else.
#4 Sara Golemion (Link) on 2007-05-19 13:02 (Reply)
I would suggest you read my article here - http://blog.assembleron.com/2007/05/14/bad-code-bad-data-flow-good-idea/
on how not to use $GLOBALS at all.
#5 Nick Halstead (Link) on 2007-05-20 04:57 (Reply)
I'm going to post a concise example that shows exactly what I observed. As it turns out, the simplified example I showed was not entirely correct, but it begins to show the issue.
#6 Matthew Weier O'Phinney (Link) on 2007-05-20 12:23 (Reply)

Add Comment

Standard emoticons like :-) and ;-) are converted to images.
E-Mail addresses will not be displayed and will only be used for E-Mail notifications

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

 
 
  • Home
  • Resume
  • Blog
  • Phly PEAR Channel
  • Contact Me
  • About this site

ZCE

Zend Education Advisory Board Member

Add to Technorati Favorites

Calendar

Back August '08 Forward
Mon Tue Wed Thu Fri Sat Sun
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31

Quicksearch

Links

  • PHLY - PHp LibrarY
  • Paul M. Jones
  • Mike Naberezny
  • Shahar Evron
  • Planet PHP
  • Zend Where I now work
  • Garden.org Where I once worked

Archives

August 2008
July 2008
June 2008
Recent...
Older...

Categories

XML Linux
XML Personal
XML Aikido
XML Family
XML Programming
XML Perl
XML PHP

All categories

Syndicate This Blog

XML RSS 0.91 feed
XML RSS 1.0 feed
XML RSS 2.0 feed
ATOM/XML ATOM 0.3 feed
ATOM/XML ATOM 1.0 feed
XML RSS 2.0 Comments

Show tagged entries

xml best practices
xml books
xml conferences
xml dojo
xml dpc08
xml file_fortune
xml linux
xml mvc
xml pear
xml personal
xml php
xml programming
xml ubuntu
xml webinar
xml zendcon
xml zend framework
© 2004 - present, Matthew Weier O'Phinney
matthew-web <at> weierophinney.net