SitePoint Sponsor

User Tag List

Results 1 to 16 of 16
  1. #1
    SitePoint Enthusiast
    Join Date
    Apr 2006
    Posts
    89
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Loading templates from a class break the code

    I just coded a class for loading template/pages; simplified:
    PHP Code:
    class tpl {
        function 
    getTpl($file) {
            include 
    'templates/'.$file;
        }
    }

    $tpl = new tpl();
    $mysql = new mysql();
    $tpl->getTpl("mytemplate.php"); 
    A template may include code like this:
    PHP Code:
    <?=$mysql->getData();?>
    Now i get "Fatal error: Call to a member function getData() on a non-object".
    From what i understand the included file works from within the tpl class and therefore it can't access the mysql class.

    What alternatives do i have, any suggestions on how to solve this?
    The solutions i have soo far:
    * Skip the tpl class and just use include 'template';
    * Send some kind of reference of mysql class to tpl class, new tpl(new mysql), but since i have around 20 classes that may or may not be used inside the template i don't like this one.

    Thanks

  2. #2
    SitePoint Enthusiast
    Join Date
    Apr 2006
    Posts
    89
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I have tried experimenting with ob_start/ob_get_clean and the Factory pattern/method but i don't see how i could get it to work.

  3. #3
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    $mysql is a variable, not a class. A class is a code-structure, like a function.
    Your template-code can't access the variable, because it's in a different scope. See variables.scope and php variable scope for an explanation.

  4. #4
    SitePoint Wizard Ren's Avatar
    Join Date
    Aug 2003
    Location
    UK
    Posts
    1,060
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    $mysql is out of scope when your template is called
    One alternative is..

    PHP Code:
    class tpl 
        private 
    $vars;

    function 
    set($name$var) { $this->vars[$name] = $var; }

       function 
    getTpl($file) { 
            
    extract($this->vars);
            include 
    'templates/'.$file
        } 


    $tpl = new tpl(); 
    $tpl->set('mysql', new mysql());
    $tpl->getTpl("mytemplate.php"); 

  5. #5
    SitePoint Enthusiast
    Join Date
    Apr 2006
    Posts
    89
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    $mysql is a variable, not a class. A class is a code-structure, like a function.
    Well actually its and object right?

    Quote Originally Posted by kyberfabrikken
    Your template-code can't access the variable, because it's in a different scope.
    Yes thats what i have figured out, what i haven't figured out is a good solution to this

  6. #6
    SitePoint Enthusiast
    Join Date
    Apr 2006
    Posts
    89
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks ren, thats worth looking into

  7. #7
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by webdevindex
    Well actually its and object right?
    Yes, an object is a specific type of variable.

    Quote Originally Posted by webdevindex
    Yes thats what i have figured out, what i haven't figured out is a good solution to this
    It's a very basic problem. I assume you're new to programming in general, or to OOP in particular ?
    When calling a function, the variable-scope changes. Normally, only variables which are declared within the current scope are accessible. If we only focus on procedural programming (no objects/classes), the scope changes when you call a function - The function has it's own scope. You have two ways of passing a variable from the calling scope and into that functions scope. Either you pass it as an argument to the function, or you declare it global. The latter is bad practice and should be avoided.
    The following should illustrate :

    PHP Code:
    function test() {
        echo 
    $foo// an undefined local variable
    }
    function 
    test2() {
        
    $foo 53// a local variable
        
    echo $foo;
    }
    function 
    test3($foo) { // the variable gets passed in as a parameter
        
    echo $foo;
    }
    function 
    test4() {
        global 
    $foo// the variable gets passed in as a global variable
        
    echo $foo;
    }
    function 
    test5() {
        global 
    $foo;
        
    $foo 53;
        echo 
    $foo;
    }
    $foo 42;
    echo 
    $foo// will output 42
    test(); // will not output anything
    $test2(); // will output 53
    echo $foo// will still output 42
    $test3($foo); // will output 42
    $test4(); // will output 42
    $test5(); // will output 53
    echo $foo// will now output 53 
    With objects, you get another option for passing variables. Since methods (functions) belongs to an object, you can assign variables to that object and use it as a "marketplace" so to speak. Consider this :
    PHP Code:
    class MyClass
    {
        var 
    $foo;
        function 
    test() {
            echo 
    $this->foo;
        }
    }
    $myObject = new MyClass();
    $myObject->foo 42;
    $myObject->test(); // will output 42 

  8. #8
    SitePoint Enthusiast
    Join Date
    Apr 2006
    Posts
    89
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    No not really but i didn't know that when using a class to include a file the included file becomes part of that class-scoop. This would make it practually impossible to use a class for loading files since the code inside that file can't access anything else. :P

  9. #9
    SitePoint Member
    Join Date
    Sep 2004
    Location
    UK
    Posts
    19
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    ...or, if you look at it another way. It's a brilliant way of restricting what is available to particular template, take the following for example.

    PHP Code:
    class Template($file) {
      private $file;

      public function __construct($file) {
        $this->file = 'templates/'.$file;
        if(!file_exists($this->file)) {
          throw new InvalidArgumentException("File not found");
        }
      }

      public function render() {
        include $this->file;
      }
    }

    $somethingsecret = "Don't tell anyone about this, it's a secret";
    $template = new Template('test.php');
    $template->myvar = 'some data';
    $template->render();

    {{{test.php}}}
    <?php
    if(isset($somethingsecret)) {
      echo(
    "$somethingsecret\n");
    } else {
      echo(
    "No secrets here, move along please\n");
    }

    if(isset(
    $this->myvar)) {
      echo(
    "You're allowed to see {$this->myvar}\n");
    } else {
      echo(
    "Nothing to see here, move along please\n");
    }
    Now, the template can only access variable you specifically say it can. You should see

    Code:
    No secrets here, move along please
    You're allowed to see some data

  10. #10
    SitePoint Wizard stereofrog's Avatar
    Join Date
    Apr 2004
    Location
    germany
    Posts
    4,324
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by webdevindex
    PHP Code:
    class tpl {
        function 
    getTpl($file) {
            include 
    'templates/'.$file;
        }
    }

    $tpl = new tpl();
    $mysql = new mysql();
    $tpl->getTpl("mytemplate.php"); 
    Why not
    PHP Code:
    class tpl {
        function 
    getTpl($file) {
            return 
    'templates/'.$file;
        }
    }

    $tpl = new tpl();
    $mysql = new mysql();
    include 
    $tpl->getTpl("mytemplate.php"); 

  11. #11
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    ...or, if you look at it another way. It's a brilliant way of restricting what is available to particular template, take the following for example.
    global $somethingsecret .. ?
    I once had a problem.
    I thought: "Oh, I know: I'll just use XML!"
    Now I had two problems.

  12. #12
    SitePoint Member
    Join Date
    Sep 2004
    Location
    UK
    Posts
    19
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Oh yea
    Must remember to think before I speak

  13. #13
    SitePoint Enthusiast
    Join Date
    Apr 2006
    Posts
    89
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for all replys, can't decide if iŽll go with stereofrog or ren's suggestion.
    Whats best? To pass the objects to the included file (ren) or to include the file in the "global scope".

    Yes i understand that this probably depends on what you want to do, but is anyone of these considered bad practice?

    Thanks again for your patience :I)

  14. #14
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    > Whats best?

    Rens example of use would proberly give you greater scope...

  15. #15
    SitePoint Guru Galo's Avatar
    Join Date
    May 2005
    Location
    Holland!
    Posts
    852
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by webdevindex
    I have tried experimenting with ob_start/ob_get_clean and the Factory pattern/method but i don't see how i could get it to work.
    That's why we have interfaces and loose typing, cool combo

    anyway,

    ob_start();

    $myNewTemplateContent = ob_get_contents();

    ob_flush_end();

    return($myNewTemplateContent);

    should do the trick, andaahh, <?=$mysql->getData();?> ?!?!?!? looks more like a static member to me in myAppp_mySqlDataManager::getData($templateID); or something like it....
    Business as usual is off the menu folks, ...

  16. #16
    SitePoint Enthusiast
    Join Date
    Apr 2006
    Posts
    89
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ok now i have tried this for a while. Right now i load all my templates inside the tpl class and in the templates i use $this->function(); so i never use functions outside the tpl scoop in the templates. But the tpl class itself might call other classes / functions.

    Example

    PHP Code:
    class tpl {
        function 
    doSomething($str)
        {
              return do::
    Something($str);
        }
        function 
    getTpl($file) {
            include 
    'templates/'.$file;
        }

    So if i want to call a class or function from inside my templates i'll add that to the tpl class. Is this bad in any way? In this case i could just use do::Something($str) inside the tempate. Don't know why i did this, maybe to have controll over whats called/running inside the template.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •