58

This (simplified version of my code) doesn't work:

<?php
    $sxml = new SimpleXMLElement('<somexml/>');

    function foo(){
        $child = $sxml->addChild('child');
    }

    foo();
?>

Why? I want to access $sxml because I want to log errors on it if foo() fails. foo() calls itself recursively to create a directory listing, so I fear passing the whole $sxml onto itself (as in foo($sxml)) could hurt performance.

Is there a way to access $sxml inside $foo without passing it as an argument? (PHP 5.2.x+)

EDIT: What if the code looks like this, actually?

<?php
    bar(){
        $sxml = new SimpleXMLElement('<somexml/>');
        function foo(){
            $child = $sxml->addChild('child');
        }
        foo();
    }
    bar();
?>
Camilo Martin
  • 34,128
  • 20
  • 104
  • 150
  • please, do OOP or just pass it as argument. Reusability is key. – mauris Mar 27 '11 at 13:40
  • @thephpdeveloper I understand your point, but I'm just getting started with PHP and this is likely not code that I'll reuse. It's more of a prototype that if goes wrong I can throw away and start from scratch. – Camilo Martin Mar 27 '11 at 13:47

5 Answers5

119

You have to pass it to the function:

<?php
    $sxml = new SimpleXMLElement('<somexml/>');

    function foo($sxml){
        $child = $sxml->addChild('child');
    }

    foo($sxml);
?>

or declare it global:

<?php
    $sxml = new SimpleXMLElement('<somexml/>');

    function foo(){
        global $sxml;
        $child = $sxml->addChild('child');
    }

    foo();
?>

If the variable isn't global but is instead defined in an outer function, the first option (passing as an argument) works just the same:

<?php
    function bar() {
        $sxml = new SimpleXMLElement('<somexml/>');
        function foo($sxml) {
            $child = $sxml->addChild('child');
        }
        foo($sxml);
    }
    bar();
?>

Alternatively, create a closure by declaring the variable in a use clause.

<?php
    function bar() {
        $sxml = new SimpleXMLElement('<somexml/>');
        function foo() use(&$xml) {
            $child = $sxml->addChild('child');
        }
        foo();
    }
    bar();
?>
Community
  • 1
  • 1
Javi R
  • 2,200
  • 1
  • 16
  • 20
  • Just one more thing... what if the variable was in a parent function? (question edited) :( – Camilo Martin Mar 27 '11 at 13:57
  • In your second example you can't access $sxml from foo() because it is locally defined in bar(). A solution could be: declare $sxml outside foo() and bar(), and use it in both functions using global. But as thephpdeveloper suggested, you should use OOP ;) – Javi R Mar 27 '11 at 14:19
20

You need to explicitly invite the global variable into the functions scope:

function foo(){
    global $sxml;
    $child = $sxml->addChild('child');
}
mario
  • 138,064
  • 18
  • 223
  • 277
4

another solution is to use $GLOBALS while you declare that variable:

         $my_var   = 'blabla';    // not global
$GLOBALS['my_var'] = 'blabla';    // global  (correct)
T.Todua
  • 44,747
  • 17
  • 195
  • 185
4

Use the global keyword to declare $sxml inside your function.

<?php
    $sxml = new SimpleXMLElement('<somexml/>');
    function foo(){
    global   $sxml;  
    $child = $sxml->addChild('child');
    }
    foo();
?>
Shamim Hafiz
  • 19,616
  • 36
  • 104
  • 164
3

While the top answer provides a nice solution, I'd like to argue that the appropriate solution in most modern PHP applications is to create a class with a static variable, like so:

<?php

class xmlHelper {
    private static $sxml;

    public function getXML() {
        return self::$sxml;
    }

    public function setXML($xml) {
        self::$sxml = $xml;
    }
}

xmlHelper::setXML(new SimpleXMLElement('<somexml/>'));

function foo(){
    $child = xmlHelper::getXML()->addChild('child');
}

foo();

This approach allows you to access $sxml from within foo() just like you wanted, but it has a few advantages over the global approach.

  1. With this strategy, you will always be able to put a breakpoint inside setXML() to find out what part of your application has manipulated this value, which you cannot do when manipulating globals.
  2. You avoid polluting the global namespace with a generic variable name sxml.
Matt Korostoff
  • 1,370
  • 2
  • 15
  • 22