tags:

views:

39

answers:

3

scope issue in PHP classes:

Why does this work?

 class index extends Application
  {
        function ShowPage()
        {
            $smarty = new Smarty();         // construct class
            $smarty->assign('name', 'Ned');     // then call a method of class
            $smarty->display('index.tpl');
        }   

}

$index_instance = new index; $index_instance->ShowPage();

but this does not work?

class index extends Application
{

    function ShowPage()
    {

        $smarty->assign('name', 'Ned');
        $smarty->display('index.tpl');
    }   
}

$index_instance = new index;
$smarty = new Smarty();
$index_instance->ShowPage();
+3  A: 

Welcome to the wonderful world of PHP variable scoping.

Functions and methods don't see any variables defined outside of them. You have to use the global keyword to declare that you want access to variables defined outside of the function scope.

This won't work:

class Foo {
    public function bar() {
        echo $baz;
    }
}
$f = new Foo();
$baz = 'Hello world!';
$f->bar(); // "Notice: Undefined variable: ..."

This will work:

class Foo2 {
    public function bar() {
        global $baz; // <- "I want $baz from the global scope"
        echo $baz;
    }
}
$f = new Foo2();
$baz = 'Hello world!';
$f->bar(); // "Hello world!"

Even though it works, you should avoid using it. There are better ways to go about passing in external object. One way is called "dependency injection", which is a fancy way of saying "pass in external dependencies during construction." For example:

class Index extends Application {
    private $smarty;
    public function __construct(Smarty $smarty) {
        $this->smarty = $smarty;
    }
    public function showPage() {
        $smarty->assign('foo', 'bar');
        $smarty->display('index.tpl');
    }
}
$sm = new Smarty(...);
$whatever = new Index($sm);
$whatever->showPage();

Another way is using a registry, which is a pattern used to store things that otherwise might be global variables. Let's try out Zend Registry as an example.

class Index extends Application {
    public function showPage() {
        $smarty = Zend_Registry::get('smarty');
        $smarty->assign('foo', 'bar');
        $smarty->display('index.tpl');
    }
}
$sm = new Smarty(...);
Zend_Registry::set('smarty', $sm);
$whatever = new Index();
$whatever->showPage();
Charles
`global` isn't for variables from the previous scope, but from the global scope.
NullUserException
Good catch, I've corrected the misleading comment.
Charles
thanks that works!
TMP File guy
+1  A: 

Simple: because $smarty doesn't exist within the scope of $index_instance.

If you want to instantiate a new Smarty outside of your index class, then you need to pass the smarty to the index instance:

class index extends Application 
{ 
    private $smarty = null;

    function __construct($smarty) {
        $this->smarty = $smarty;
    }

    function ShowPage() 
    { 

        $this->smarty->assign('name', 'Ned'); 
        $this->smarty->display('index.tpl'); 
    }    
} 

$smarty = new Smarty(); 
$index_instance = new index($smarty); 
$index_instance->ShowPage(); 
Mark Baker
A: 

I am now using dependency injection method.

require_once("/classes/Conf.php");
require_once("/classes/Application.php");

class index extends Application
{
    private $template_instance;

    public function __construct(Smarty $template_instance)
    {
        $this->template_instance = $template_instance;
    }

    function ShowPage()
    {
        $this->template_instance->assign('name', 'Ned'); 
        $this->template_instance->display('index.tpl'); 
    }   
}

$template_instance = new Smarty();
$index_instance = new Index($template_instance);
$index_instance->showPage();
TMP File guy