1. Advertising
    y u no do it?

    Advertising (learn more)

    Advertise virtually anything here, with CPM banner ads, CPM email ads and CPC contextual links. You can target relevant areas of the site and show ads based on geographical location of the user if you wish.

    Starts at just $1 per CPM or $0.10 per CPC.

Class Variable Scope - Include Files

Discussion in 'PHP' started by Key Lime Pie, Aug 14, 2010.

  1. #1
    Hello! I did a brief search but couldn't find an exact answer to my problem. I'm aware of how include files work in PHP; that they are litteraly included onto the including page as if they were one. Variables that are created in the including file 'before' the include happens are usable by the included file. I've used this, tested it, it works fine.

    Problem is on the current site module I am developing for a client it doesn't work and I think it may have something to do with it being a class. Here is the exact structure...
    SEMrush
    Main Page: results.php (includes class pages and result pages)
    Class Pages: Root.php (main class that has all other class data stored)
    • Data.php
    • Calculation.php
    • Display.php
    Result Pages
    • high_risk.php
    • low_risk.php
    • etc

    results.php first includes Root.php and then later includes various result pages based on conditions. $root is created after including Root.php but is unusable by the included result pages.

    
    results.php
    <?php
    require 'Root.php';
    $root = new Root();
    
    $root->doStuff();
    ?>
    
    // Some HTML
    
    <?php $root->displayResults(); ?> // Includes result pages for display.
    
    PHP:
    
    Result Pages
    // HTML
    <?php echo $root->getUser('firstname'); ?>
    // HTML
    
    PHP:
    When a result page is included onto results.php I get an error saying $root is undefined. If I make a new instance of $root on the result page it works fine. Problem with that is it resets the data handling done by root in the original $root->doStuff(); call. I can repeat this on each result page but that's a lot of extra work for the server that shouldn't be needed. Anyone have an idea as to why the $root variable looses scope?
     
    Key Lime Pie, Aug 14, 2010 IP
    SEMrush
  2. Rainulf

    Rainulf Active Member

    Messages:
    373
    Likes Received:
    12
    Best Answers:
    0
    Trophy Points:
    85
    #2
    I'm guessing displayResults( ) function contains include statements. This will never work because $root inside the function doesn't exist, it's calling the local variable $root not the global variable $root. See this for more information. However, you can do this instead on your Result pages:
    
    <?php echo $this->getUser('firstname'); ?>
    
    PHP:
    Since the Result pages are part of the class, $this keyword should work.
     
    Last edited: Aug 15, 2010
    Rainulf, Aug 15, 2010 IP
    Key Lime Pie likes this.
  3. Key Lime Pie

    Key Lime Pie Peon

    Messages:
    4
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    0
    #3
    Oh wow, that's a really strange issue. It makes sense, sort of, but I had assumed it just put it on the new page without any scope issues. I've never created a solution like this before so I've had some issues. I do have another question if you don't mind...

    How the code works is there are classes for data (db stuff), calculation (figuring out scores), and display (including various files based on scores). The root class has methods for accessing and utilizing these classes inside of itself. For instance Root::displayResults() calls all of the other display functions and passes them scores from the calculations class. That being said the includes are technically going through Root:: Display::showTestName(). calling $this-> tells me Display::getUser() is undefined. Even though get user is a part of Root.

    I'm considering adding a showUser() function to the display class and trying that. Is there any way you would do this solution that I may be missing? Thank you in advance for any help on the subject.
     
    Key Lime Pie, Aug 16, 2010 IP
  4. Rainulf

    Rainulf Active Member

    Messages:
    373
    Likes Received:
    12
    Best Answers:
    0
    Trophy Points:
    85
    #4
    I can't exactly visualize your class design, but $this should be possible if you derived your Display class from the Root class.

    eg:
    
    <?php
    class lol {
       public function poop( ) {
          echo "Echo from base... <br />";
       }
    }
    
    class lmao extends lol {
       public function haha( ) {
          echo "Echo from derived... <br />";
       }
    }
    
    $a = new lmao( );
    $a->poop( );
    $a->haha( );
    ?>
    
    PHP:
    I haven't tried parent keyword yet, but you can also try it with that.
     
    Rainulf, Aug 16, 2010 IP
  5. Key Lime Pie

    Key Lime Pie Peon

    Messages:
    4
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    0
    #5
    I'll try to give you a better picture.

    
    class Root {
       private $data;
       private $calc;
       private $display;
    
       private $userData;
       private $userAnswers;
       private $userScores;
    
       public function __construct() {
          $this->data = new FreyaDatabase();
          $this->calc = new Calculation();
          $this->display = new Display();
       }
    
       // A bunch of functions to get data from the database, pass that data to the calc
       //    class, then pass the scores returned from the calc class to the display class
       //    for processing into proper result page includes.
    
       public function displayResults() {
          $this->display->showTestOneResults($this->userScores['testone']);
          $this->display->showTestTwoResults($this->userScores['testtwo']);
          $this->display->showTestThreeResults($this->userScores['testthree']);
       }
    }
    
    class Display {
       public function showTestOneResults($score) {
          if ($score >= 9) {
             include 'high_results.php';
          }
          elseif ($score >= 5) {
             include 'medium_results.php';
          }
          etc
       }
    }
    
    PHP:
    So that's the basic idea. I wanted to keep it modular so I separated things like calculations and display into different classes. Then to make it easy to pass data between them I just made a root class that could handle almost the entire process in just a couple calls. I may just need to take it all out of root and call them manually though huh?
     
    Key Lime Pie, Aug 16, 2010 IP
  6. Rainulf

    Rainulf Active Member

    Messages:
    373
    Likes Received:
    12
    Best Answers:
    0
    Trophy Points:
    85
    #6
    Interesting! Well, if you don't wanna derive your classes, then maybe we can cheat a little. You can use global keyword:
    
    global $root; // refers now to $root global
    echo $root->display->getUser('firstname'); 
    
    PHP:
    $display and the other two are private, so calling those directly isn't possible. You have to change those three classes to public.

    Your other option is to derive:
    
    class Root {
    
       protected $userData;
       protected $userAnswers;
       protected $userScores;
    
       public function __construct() { }
    
       // A bunch of functions to get data from the database, pass that data to the calc
       //    class, then pass the scores returned from the calc class to the display class
       //    for processing into proper result page includes.
    
       public function displayResults() {
          $this->display->showTestOneResults($this->userScores['testone']);
          $this->display->showTestTwoResults($this->userScores['testtwo']);
          $this->display->showTestThreeResults($this->userScores['testthree']);
       }
    }
    
    //  Or just extend Root
    class FreyaDatabase extends Root { }
    class Calculation extends FreyaDatabase { }
    class Display extends FreyaDatabase {
       public function showTestOneResults($score) {
          if ($score >= 9) {
             include 'high_results.php';
          }
          elseif ($score >= 5) {
             include 'medium_results.php';
          }
          etc
       }
    }
    //
    //  Or just extend Root
    
    PHP:
    $this will be possible:
    
    <?php echo $this->getUser('firstname'); ?>
    
    PHP:
    In any case, it's your choice. There's tons of options. :)
     
    Rainulf, Aug 16, 2010 IP
  7. Key Lime Pie

    Key Lime Pie Peon

    Messages:
    4
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    0
    #7
    Alright! I'll try those and post how it goes. Thank you for all of your help it's been so amazing. On that note though do you think using something like a root class isn't a good idea? I try and keep my code as modular and abstracted as possible so I love the concept but I have problems with it occasionally.
     
    Key Lime Pie, Aug 16, 2010 IP
  8. Rainulf

    Rainulf Active Member

    Messages:
    373
    Likes Received:
    12
    Best Answers:
    0
    Trophy Points:
    85
    #8
    I personally find it refreshing because I haven't tried it that way before, it keeps everything in place and organized. I say go for it, explore different concepts! :)
     
    Rainulf, Aug 16, 2010 IP