OOP Inheritence and HTTP_REFERER

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Nay
Forum Regular
Posts: 951
Joined: Fri Jun 20, 2003 11:03 am
Location: Brisbane, Australia

OOP Inheritence and HTTP_REFERER

Post by Nay »

I have two questions that I've come to ponder over. Anyway,

First:

I have a similar code like:

Code: Select all

Class Foo {
   var $Bar = 'foo';
}

Class Bar extends Foo {
   function Bar {
      $this->Bar = 'fooey';
   }
}

$Foo = new Foo();
$Bar = new Bar();
print $Foo->Bar;
When I tested that out the value of Foo::Bar is still 'foo' and not 'fooey' as I supposedly changed it. Why is it? If it's not possible, how can I change a parent variable from a child class?

Second:

For some odd reason. I did a phpinfo() on both my local server and host server and I do not find $_SERVER['HTTP_REFERER'] anywhere. I swear that variable is present a while back. phpinfo();

http://frozenashes.net/paul/php.php

Any explanation to this?

Thanks,

-Nay
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post by McGruff »

$Foo doesn't know it's a superclass. If you instantiate it alone, the Bar class isn't involved in any way.

Add another line to your code above:

Code: Select all

<?php
$Foo = new Foo();
$Bar = new Bar();
print $Foo->Bar; 
print $Bar->Bar; 
?>
Last edited by McGruff on Tue Aug 09, 2005 10:04 am, edited 1 time in total.
User avatar
Weirdan
Moderator
Posts: 5978
Joined: Mon Nov 03, 2003 6:13 pm
Location: Odessa, Ukraine

Re: OOP Inheritence and HTTP_REFERER

Post by Weirdan »

Nay wrote: For some odd reason. I did a phpinfo() on both my local server and host server and I do not find $_SERVER['HTTP_REFERER'] anywhere. I swear that variable is present a while back. phpinfo();
$_SERVER['HTTP_REFERER'] is not getting set if you just enter the URL into the address bar. Make the page which have <a href="you_phpinfo_script.php">Click</a> in it. Then click the link and see your HTTP_REFERER ;)
Nay
Forum Regular
Posts: 951
Joined: Fri Jun 20, 2003 11:03 am
Location: Brisbane, Australia

Post by Nay »

McGruff, I get it now. In this case it prints out the 'Bar', from the child class Bar, which was inherited. So in other words a parent class cannot reply on a child class? So If I wanted some 'connection' between classes, where one is able to access another's variables, how would you go about doing it?

Wierdan, thanks for the note. How would I check/would it work if it was like:

Code: Select all

<img src="myscript.php" />
-Nay
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post by McGruff »

Aha! The million dollar question.

See this article for a quick summary of combining classes. Have a look through the rest of the site for some ideas about combining classes using design patterns. The factory method is possibly a good place to start since it's one of the simplest and most common.

Association is often better than inheritance - it depends. It sounds like that's what you're after.

At its simplest, if class A needs to a get hold of a var in class B, just write a getter method in B. Return by reference if you want the value in A to be updated when B changes state.

I'd need to learn more about what you are trying to do before I could say anything else.
Nay
Forum Regular
Posts: 951
Joined: Fri Jun 20, 2003 11:03 am
Location: Brisbane, Australia

Post by Nay »

This is when my question popped up. If you don't mind I sure will take a look at your link later. Right now I'm switching between my history project due in 3 hours and OOP (A very hard decision isn't it? ;)).

Anyway one of the classes:

Code: Select all

Class HTML extends Config {

   var $logHTML = null;
   var $infoHTML = null;
   var $linksHTML = null;

   var $hitsToday = 0;
   var $iTotalHits = 0;

   function HTML($resultArray) {

      if(empty($resultArray)) {

         $this->logHTML = '<span class="error">No logs found for today (' . date($this->timeFormat) . ')</span>';
         return true;

      }

      $resultArray = array_reverse($resultArray);

      if(isSet($_GET['date'])) {
         $date = $_GET['date'];
         $date = $date[0] . $date[1] . '-' . $date[2] . $date[3] . '-' . $date[6] . $date[7];
      } else {
         $date = date('d-m-Y');
      }

      // Start result table
      $return = <<< RETURN

      <b class="dateHeader">{$date}</b><br /><br />

   <table cellpadding="1" cellspacing="0" border="0" id="resultTable">
      <tr>
         <th class="resultTh">Visitor Username</th>
         <th class="resultTh">Visit Time</th>
         <th class="resultTh">Visitor IP</th>
         <th class="resultTh">Resolution</th>
         <th class="resultTh">Browser</th>
      </tr>

RETURN;

      // Start loop and begin adding results
      for($i = 0; $i < count($resultArray); $i++) {

         // Break up log data
         $logString = explode(' | ', $resultArray[$i]);

         if(empty($logString[0])) {
            continue;
         }
         
         // Determine row color
         if($i % 2) {
            $rowClass = 'default';
         } else {
            $rowClass = 'alternate';
         }

         // Format name
         if($logString[0] == 'xanga') {
            $name = 'Guest';
         } else {
            $name = '<a href="http://www.xanga.com/home.aspx?user=' . $logString[0] . '" target="_blank">';
            $name .= $logString[0];
            $name .= '</a>';
         }

         // Format time
         $time = date($this->timeFormat, $logString[1]);

         // Add row to table
         $newRow = <<< NEWROW

      <tr>
         <td class="{$rowClass}">
            <span class="result_username">{$name}<span>
         </td>
         <td class="{$rowClass}">
            <span class="result_time">{$time}</span>
         </td>
         <td class="{$rowClass}">
            <span class="result_ip">{$logString[2]}</span>
         </td>
         <td class="{$rowClass}">
            <span class="result_ip">{$logString[3]}</span>
         </td>
         <td class="{$rowClass}">
            <span class="result_ip">{$logString[4]}</span>
         </td>
      </tr>

NEWROW;

         // Add result
         $return .= $newRow;

      }

      // End table
      $return .= '</table>';

      // Set and return $return
      $this->logHTML = $return;
      $this->hitsToday = count($resultArray);

      return $return;

   }

   function CompileInfo() {

      $this->infoHTML = <<< INFO
      <b>Hits Today:</b> {$this->hitsToday}<br />
      <b>Total Hits:</b> {$this->iTotalHits}
INFO;

   }

   function totalHits() {

      // Set total hits in rerference to iTotalHits
      $totalHits =& $this->iTotalHits;

      // Open dir and calculate hits in each file
      $dh = opendir($this->logFolder);

      while($file = readdir($dh)) {
         if(is_file($this->logFolder . '/' . $file)) {
            $totalHits += count(file($this->logFolder . '/' . $file));
         }
      }

   }

   function CompileLinks() {

      // Set counter and add reference to linksHTML variable
      $counter = 0;
      $links =& $this->linksHTML;

      $dh = opendir($this->logFolder);

      while($file = readdir($dh)) {
         if(is_file($this->logFolder . '/' . $file)) {
            if($counter <= $this->maxLinkDisplay) {
               $date = str_replace('.txt', '', $file);
               $linkDate = $date[0] . $date[1] . '-' . $date[2] . $date[3] . '-' . $date[6] . $date[7];
               $links .= '<a href="index.php?date=' . $date . '">' . $linkDate . "</a>\n";
               $counter++;
            } else {
               break;
            }
         }
      }

   }

   function CompilePage() {

      // Extract template HTML
      $templateHTML = implode("", file($this->templateFile));

      // Check if results are set or not
      if(empty($this->logHTML)) {
         die('Warning: Fatal error calling method CompilePage() before results HTML is compiled.');
      }

      // Compile page
      $templateHTML = str_replace('{TITLE}', 'XFnet Counter 1.0.6 Beta', $templateHTML);
      $templateHTML = str_replace('{LINKS}', $this->linksHTML, $templateHTML);
      $templateHTML = str_replace('{INFO}', $this->infoHTML, $templateHTML);
      $templateHTML = str_replace('{RESULTS}', $this->logHTML, $templateHTML);

      return $templateHTML;

   }

}
This is the HTML class, one which is supposed to handle the templating part of the app. The app is a simple flat file based counter I made up - including a view stats area. Anyhow, the totalhits() is a method not related to HTML at all. It 'was' in the Logger class before but I was unable to set the final variable iTotalHits from the child class therefore I moved the method into the parent class - temperorily.

I hope this gives you a clearer view of what I'm doing (as well as my ametuer OOP :lol:). I'd welcome advice on my current situation as well as any flaw or bad pratice you see in my code.

Thanks,

-Nay
Nay
Forum Regular
Posts: 951
Joined: Fri Jun 20, 2003 11:03 am
Location: Brisbane, Australia

Post by Nay »

Wow, McGruff, I woke up at 5 in the morning and got 4 hours of sleep to read your link - really worth it :P.

I never realised how:

Code: Select all

<?php
class Debug {
    function display () {
        echo ($this->errorMsg);
    }
}

class SomeClass {
    var $errorMsg='This is an error message';
    function someFunction () {
        if ( DEBUG == 1 ) {
            Debug::display();
        }
    }
}

define ('DEBUG',1);
$someClass= &new SomeClass;
$so
can be done. I would ask, how did the var $errorMsg get passed? The funtion 'someFunction()' mere called a function in another class but the variables of the someClass was passed onto the Debug class? eh..

-Nay
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post by McGruff »

Nay wrote: I hope this gives you a clearer view of what I'm doing (as well as my ametuer OOP :lol:). I'd welcome advice on my current situation as well as any flaw or bad pratice you see in my code.

-Nay
First, some refactoring to disentangle various threads. Two aims:

(1) separate out discrete tasks into individual functions
(2) separate business logic (model) from presentation logic (view)

The classes below cover the biz logic only.

Not tested and may have bugs. The point is just to give you some ideas about how to structure a class. The general principle is that each function - or class - should do just one thing.

I haven't been consistent with var names - some camel back (as you have written) but I couldn't stop myself writing some underscore-separated. This is one of those personal preference things: I always write vars the latter way but fn names the former.

Code: Select all

<?php
$this->error_report;   // a var less likely to be confused with..
$this->errorReport(); // a method
?>
The way private &amp; public methods are separated below is again just my own way of working. Private method names always start with an underscore and there's a dirty great comment block separating the two groups. I find it helps to highlight the class interface (ie the public methods). In php there is no difference between private &amp; public of course, hence there is possibly a need to do something of this kind.

Code: Select all

<?php

/*
    CLASS PageVars

    No methods - just properties. Putting page vars in their own class helps
    to focus on what is actually to be output on the page by providing an
    at-a-glance list. This gets more useful the more complicated is the
    model. (I hope I didn't miss any page vars in your original script).
    
    Not a standard OOP practice or anything just something I like to do.

    This is one of the very few cases where I wouldn't bother with getters
    and setters for class properties.
*/
class PageVars 
{
    var $hits_today = 0;
    var $total_hits = null;    
    var $message    = null;       
    var $date       = null;
    var $row_vars   = null;      
    var $log_links  = null;     
}
///////////////
// END CLASS //
///////////////


/*
    CLASS: HTML

    I don't know what was in the previous Config class - I'm guessing you
    don't really need to extend a base class.

    The class name probably ought to be changed from "HTML" to
    LogReport or something along those lines. Naming is very important 
    once you start encapsulating. The whole point is to hide a bunch of
    functionality behind an interface: a good name explains what's under
    the bonnet without having to look, a bad one leaves you wondering
    what's going on.
*/
Class HTML
{
    var $log_folder     = 'path/to/file.php'; // or pass var to constructor if not constant
    var $max_log_links  = 20; // or whatever
    var $date_format    = 'd-m-Y';
    
    /*
        param (array) $resultArray
    */
    function HTML($resultArray) 
    {
        $this->resultArray  =  array_reverse($resultArray); #?
        $this->page_vars    =& new PageVars;
    }

    function setPageVars() 
    {
        $this->page_vars->hits_today    = count($this->resultArray);
        $this->page_vars->total_hits    = $this->_totalHits();
        $this->page_vars->message       = $this->_message();
        $this->page_vars->date          = $this->_date();
        $this->page_vars->row_vars      = $this->_rows();
        $this->page_vars->log_links     = $this->_logLinks();
    }

    function &getPageVars() 
    {
        return $this->page_vars;
    }

    //////////////////////////////////////////
    //              PRIVATE                 //
    //////////////////////////////////////////

    /*
        return (integer)
    */
    function _totalHits() 
    {
        $total_hits = 0;
        $dh         = opendir($this->logFolder);

        # replaced: while($file = readdir($dh)) - see php manual
        while (false !== ($file = readdir($dh)))
        {
            if(is_file($this->logFolder . '/' . $file)) 
            {
                $total_hits += count(file($this->logFolder . '/' . $file));
            }
        }
        return $total_hits;
    }

    /*
        html formatting (the span tag) has been removed from the message

        return (string)
    */
    function _message()
    {        
        if(empty($this->resultArray))
        {
            $message  = 'No logs found for today (';
            $message .= date($this->date_format);
        
        } else {
        
            $message = null;
        }
        return $message;
    }

    /*
        return (string)
    */
    function _date() 
    {        
        if(isset($_GET['date'])) 
        {
            $date  = $_GET['date'][0] . $_GET['date'][1] . '-';
            $date .= $_GET['date'][2] . $_GET['date'][3] . '-';
            $date .= $_GET['date'][6] . $_GET['date'][7];

        } else {

            $date = date($this->date_format);
        }
        return $date;
    }

    /*
        return (array)
    */
    function _rows()
    {        
        $rows   =  array();
        $row    =& new Row($this->time_format);

        for($i = 0; $i < count($this->resultArray); $i++) 
        {
            # $logString isn't a string - it's an array - so let's call it $log to avoid confusion
            $log = explode(' | ', $this->resultArray[$i]);
            $rows[$i] = $row->getRow($log, $i);
        }
        return $rows;
    }

    function _logLinks() 
    {
        $ob =& new LogLinks($this->log_folder, $this->max_log_links);
        $ob->setLinks();

        return $ob->getLinks();
    }
    
}
///////////////
// END CLASS //
///////////////


/*
    CLASS Row

    Defines page vars for the current table row.

    These methods work together and probably deserve a class of their 
    own - also LogLinks class. 
*/
class Row 
{
    /*
        param (string) $time_format
    */
    function Row($time_format) 
    {
        $this->time_format = $time_format;
    }
    
    /*
        param (array) $log
        param (integer) $i
        return (array)
    */
    function getRow($log, $i) 
    {        
        $row            = array();
        $row['name']    = $this->_name($log[0]);
        $row['time']    = date($this->timeFormat, $log[1]);
        $row['ip']      = $log[2];
        $row['res']     = $log[3];
        $row['browser'] = $log[4];

        return $row;
    }
    
    //////////////////////////////////////////
    //              PRIVATE                 //
    //////////////////////////////////////////

    /*
        Frequently there are if tests before setting a var. It's usually best to
        refactor the logical test and the actions to be performed in each case
        into separate functions (unless it's something trivial like 
        $name = 'Guest' which doesn't need it's own fn). Fns should do just
        one thing: the logical test is obscured if you add in the actions in the
        same fn. Another method _hyperlinkName carries out the task of
        setting the hyperlink.

        param (string) $name
        return (string)
    */
    function _name($name) 
    {        
        if($name == 'xanga') 
        {
            return 'Guest';

        } else {

            return $this->_hyperlinkName($name);
        }
    }

    /*
        param (string) $name
        return (string)
    */
    function _hyperlinkName($name) 
    {        
        $link  = '<a href="http://www.xanga.com/home.aspx?user=';
        $link .= $name;
        $link .= '" target="_blank">';
        $link .= $name;
        $link .= '</a>';

        return $link;
    }         

}
///////////////
// END CLASS //
///////////////
    

/*
    CLASS LogLinks

    Links to log reports?
*/
class LogLinks 
{
    // public
    var links = '';
    

    function LogLinks($logFolder, $max) 
    {
        $this->logFolder    = $logFolder;
        $this->max          = $max;
    }
    
    function setLinks() 
    {
        $counter    = 0;
        $dh         = opendir($this->logFolder);

        # replaced: while($file = readdir($dh)) - see php manual
        while (false !== ($file = readdir($dh)))
        {
            if(!is_file($this->logFolder . '/' . $file)) 
            {
                break;
            }
            if($counter > $this->max) 
            {
                return;
            }
            $this->links .= $this->_logLink($file);
            $counter++;
        }
    }

    /*
        return (string)
    */
    function getLinks() 
    {
        return $this->links;
    }

    //////////////////////////////////////////
    //              PRIVATE                 //
    //////////////////////////////////////////
        
    function _logLink($file) 
    {
        $date       = str_replace('.txt', '', $file);
        $linkDate   = $date[0] . $date[1] . '-';
        $linkDate  .= $date[2] . $date[3] . '-';
        $linkDate  .= $date[6] . $date[7];
        
        return '<a href="index.php?date=' . $date . '">' . $linkDate . "</a>\n";
    }

}
///////////////
// END CLASS //
///////////////   


/*
    In use:
*/
$report_page =& new HTML($resultArray);
$report_page->setPageVars();
$page_vars =& $report_page->getPageVars();

?>
That takes care of the business logic or model. The model output should be a bunch of format-free vars (let's just gloss over the hyperlinks and date formatting for now...).

Next, the view where formatting is applied to the model and the page is printed. You could include an html template with embedded echo calls such as:

Code: Select all

&amp;lt;?php echo $page_vars-&amp;gt;log_links; ?&amp;gt;
You'll need a presentation function to loop through $row_vars array, printing one row at a time. In the template just call the fn and pass the $row_vars:

Code: Select all

&amp;lt;?php echo printTableRows($page_vars-&amp;gt;row_vars); ?&amp;gt;
Embedded echo's &amp; looping fns for data rows creates a very simple (but perfectly respectable) templating system. However, with a separate model (all the code which defines the unformatted page vars) and view (html templates &amp; presentation fns), you can easily change to another system. The same model output (the $page_vars class in this case) can be packed off to any kind of view. Code has become more modular. It's easier to read because different threads have been disentangled. Html designers can now work on the html templates without having to read through any php files - and there's no html obscuring what's going on in the model code. If you ever want pdf or xml pages, you can easily create the appropriate templates and re-use the same model.

This doesn't answer your original question but, before you can consider how to combine classes in an OOP design, you have to figure out the component classes. This is usually quite a fluid stage where ideas can change as you think about the problem so it's often best not to write any code at all - simply define some interfaces. A UML diagram (see above link) can be a good way to start.
Last edited by McGruff on Tue Aug 09, 2005 10:00 am, edited 3 times in total.
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post by McGruff »

Nay wrote:Wow, McGruff, I woke up at 5 in the morning and got 4 hours of sleep to read your link - really worth it :P.

I never realised how:

Code: Select all

<?php
class Debug {
    function display () {
        echo ($this->errorMsg);
    }
}

class SomeClass {
    var $errorMsg='This is an error message';
    function someFunction () {
        if ( DEBUG == 1 ) {
            Debug::display();
        }
    }
}

define ('DEBUG',1);
$someClass= &new SomeClass;
$so
can be done. I would ask, how did the var $errorMsg get passed? The funtion 'someFunction()' mere called a function in another class but the variables of the someClass was passed onto the Debug class? eh..

-Nay
When you call a static fn, the class isn't actually instantiated and so "$this" has no meaning inside a statically-called method.

You could do this though:

Code: Select all

<?php
class Debug 
{
    function display ($message) 
    {   
        echo ($message);
    }
}

class SomeClass 
{
    var $errorMsg='This is an error message';
    
    function someFunction () 
    {
        if ( DEBUG == 1 ) 
        {
            Debug::display($this->errorMsg);
        }
    }
}
If SomeClass inherited Debug your code would be OK.
Last edited by McGruff on Tue Aug 09, 2005 9:55 am, edited 1 time in total.
Nay
Forum Regular
Posts: 951
Joined: Fri Jun 20, 2003 11:03 am
Location: Brisbane, Australia

Post by Nay »

McGruff, thanks for taking time to re write out the class. I really appriciate it. I generally understand how you organized the class - I guess. I'm reading up articles on phppatterns.com - which are really interesting.

Anyhow, I'd like to ask about UML. Do you use any specific software to draw it? Say I just launch Photoshop and start drawing the lines and boxes according to standard?

Another thing, I had a topic asking about reference. I understand the:

Code: Select all

$a =& $b;

$Foo = &new Foo();

function (&$var) {
   // bla
}
but what about:

Code: Select all

function &Foo() {
   $bar = 'foo';
}
When you call that function, what is supposed to happen? The function Foo() references to a variable? Er, probably not.

And then I noticed that you removed table formatting. When you need to generate a table, how do you go about doing it?

Then you asked about the config class. Well the config class contains all the variables necessary for the application itself. Is that a good pratice? Or should I state the variables in each class instead? I thought of this as 'easier' since I won't have to hunt down all of my class files to change a variable. So it has my MySQL connection varialbes, path and url information, time and date formats, and some flags for methods.

Thanks for your time,

-Nay
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post by McGruff »

Nay wrote:I'd like to ask about UML. Do you use any specific software to draw it? Say I just launch Photoshop and start drawing the lines and boxes according to standard?
I just use Freehand to sketch out UML diagrams - "drawing" might be easier to edit than "painting". I think phpatterns might have had a link to a proper UML program.
Another thing, I had a topic asking about reference. I understand the:

Code: Select all

$a =& $b;

$Foo = &new Foo();

function (&$var) {
   // bla
}
but what about:

Code: Select all

function &Foo() {
   $bar = 'foo';
}
This would be used to return a reference:

Code: Select all

function &getFoo() 
{
   return $foo;
}
And then I noticed that you removed table formatting. When you need to generate a table, how do you go about doing it?
I wanted to concentrate on the model above and didn't write any presentation stuff. In the page's html template, add <table> tags, the first (static?) title row, and then call a simple printRows() fn to print the rows with dynamic content (another template, more embedded echo's):

Code: Select all

printRows($rows, $template)
{
    foreach($rows as $row)
    {
        include($template);
    }
}
There are various approaches to templating many of which are unecessarily complex. Embedded echo's - and the occasional presentation fn when needed - is simple but quite acceptable.
Then you asked about the config class. Well the config class contains all the variables necessary for the application itself. Is that a good pratice? Or should I state the variables in each class instead? I thought of this as 'easier' since I won't have to hunt down all of my class files to change a variable. So it has my MySQL connection varialbes, path and url information, time and date formats, and some flags for methods.
As a rule, you want to minimise variable scope as much as possible. The more places a variable exists, the more potential problems there are. In a complex application with many objects, global variables, for example, could be altered by anything. That is very difficult to debug. Global variables shouldn't really be used at all.

Constants are OK though. Once defined they can't be altered. Much of the stuff you mentioned I think is the kind of thing I'd define as constants but encapsulating in a class is also valid.

If you find you need a config class it might be a candidate for a singleton (explained on phppatterns; there's also something in the code snippets board). However, singletons can create some of the problems one has with global vars so avoid unless passing args in to classes and methods is getting really awkward.
Last edited by McGruff on Tue Aug 09, 2005 9:46 am, edited 1 time in total.
Nay
Forum Regular
Posts: 951
Joined: Fri Jun 20, 2003 11:03 am
Location: Brisbane, Australia

Post by Nay »

I read this:

http://phppatterns.com/index.php/articl ... iew/6/1/1/

Is it the right article? First it explain about one global instance. It still had me there but when it went onto DOM functions, it totally lost me. And it stated use with caution? I'm scared :\

-Nay
malcolmboston
DevNet Resident
Posts: 1826
Joined: Tue Nov 18, 2003 1:09 pm
Location: Middlesbrough, UK

Post by malcolmboston »

Nay wrote: I'm scared :\
lol
User avatar
patrikG
DevNet Master
Posts: 4235
Joined: Thu Aug 15, 2002 5:53 am
Location: Sussex, UK

Post by patrikG »

Nay wrote:I read this:

http://phppatterns.com/index.php/articl ... iew/6/1/1/

Is it the right article? First it explain about one global instance. It still had me there but when it went onto DOM functions, it totally lost me. And it stated use with caution? I'm scared :\

-Nay
Get your head around OOP first before you start on patterns. Patterns are scary at first (I sit in the corner with closed eyes and shivering almost daily ;)), but the important point is that you'll know the tools you have. Once you've programmed a bit using OOP, you'll find patterns like singleton, MVC, iterator etc. easier to understand.

Patterns are solutions to common problems - expressed, generally, in an abstract way. They help you design your application but make your code much more abstract, but much more adaptable and thus powerful.
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post by McGruff »

A lot of the patterns don't start to make sense until the second reading or so. The good news is that singletons are very simple - you can forget all about the DOM.

Code: Select all

<?php

function &singleton($class_name)
{
    static $ob;

    if(!isset($ob))
    { 
        $ob = new $class_name;
    } 
    return($ob);
}
?>
That assumes the class definition has already been included. Since it's going to be used as a singleton, it would be included (somewhere) as standard for all scripts.

You can only use this fn for a single singleton: if you need more than one you'll need another function as above per singleton - or something like the singleton pool in code snippets.

Singletons are effectively superglobal so you can do this anywhere you need the Config class:

Code: Select all

<?php

$config =& singleton('Config');

?>
Last edited by McGruff on Tue Aug 09, 2005 9:45 am, edited 1 time in total.
Post Reply