Web Tutorials     [RO]  [EN]  
| HOME | Tutorials | News | SERVICES | Directory | Tools | FORUM | About | SITE MAP | CONTACT | SEARCH |
.....................................................
.....................................................
User happy birthdayToday we celebrate one day of birth.
(dannyb0y)
.....................................................
Login
Register
I forgot my password
.....................................................
Put your ad here
.....................................................
Online
In total there is
10 visitors online,
of which:
1 invited
9 are bots
.....................................................
Put your ad here
.....................................................
.....................................................
.....................................................
.....................................................
.
Home - PHP 5, Factory

<< PHP-Java interoperability   -   PHP 5, SQLite in Factory? >>
Rate this article(Members only)
1 2 3 4 5
A - A Announced this way the site administrator for any problems observed on this page.  Print this page as PDF  Email  

PHP 5, Factory


Publishing date: 08-02-2011 - Copyright © Aurelian

I will try during this tutorial to explain various techniques introduced in PHP 5 that I like to use (or I would like).
The reason?
Next time I'll need something like that I can find it quickly and get documented with the information necessary, given that at some point i'll lose these things through a corner of the HDD.

I. Definitions

I'll try to respect the rules exactly as published under the name of Coding Standards on the PEAR website.
The "inline" classes, methods and attributes documentation is very useful when I read the source code of a file written six months ago.
I usually use phpDocumentor to generate php code documentation professionally.

II. Intro

The first example presented in this series refers to the concept of factory implementation in php. This example is not complete and can not be considered a standard example of the "factory" idea.
To answer my questions "What is a Factory?", " At what does it helps me?", "Is it useful?", "is it worth it?" i read the article "The Factory Method" by Harry Fuecks.

I read carefully the code posted there, and I read these pages that are part of the presentation "2002 International PHP Conference: Applied OO PHP: APIs, Design Patterns and Useful Objects - Chuck Hagenbuch.
Google also brought me some interesting articles.
Finally, I decided to implement an example written in Java.
For testing, i'll use php CLI and a directory called trace_factory.

III. Interface.

From the documentation in hand, through an interface we can create an object that specifies which methods a class must implement, without defining the behavior of these methods.
Translation of Java in PHP 5 interface looks like:

CODE:
<?php
/**
* Is the Trace Interface
* It contains common methods for every implementation
* @package test.factory.trace
* @access public
*/

interface Trace {
   /**
   * Turn on and off debugging
   * @param bool debug
   */
   public function setDebug($debug);
   /**
   * Write out a debug message
   * @param string message to debug
   */
   public function debug($message);
   /**
   * write out an error message
   * @param string message to debug
   */
   public function error($message);
}
?>

I saved this file: ITrace.php name.

Continuing the example, we will write two implementations, in the first, the messages will be displayed in the console (or in the web page if we drop CLI ) and the second it will write the messages to a text file.

IV. StdoutTrace.php

CODE:
<?php
include_once('ITrace.php');
/**
* It display the trace to stdout
*
* @package test.factory.trace
* @access public
*/

class StdoutTrace implements Trace {
   /**
   * debug
   * @var bool
   * @access private
   */
   private $debug;
   /**
   * Sets the debug
   * @param bool debug
   * @return void
   * @access public
   */
   public function setDebug($debug) {
      $this->debug = $debug;
   }
   /**
   * It writes a debug message
   * only if debug is setted to true
   * @param string message
   * @return void
   * @access public
   */
   public function debug($message) {
      if($this->debug) {
         // only print if debug is true
         echo date("d-m-Y H:i:s")." DEBUG >>>>".$message."\n";
      }
   }
   /**
   * It writes an error message
   *
   * @param string message
   * @return void
   * @access public
   */
   public function error($message) {
      // always print out errors
      echo date("d-m-Y H:i:s")." ERROR >>>>".$message."\n";
   }
}
?>

I saved the file with the name StdoutTrace.php the same directory.

V. FileTrace.php

CODE:
<?php
include_once('ITrace.php');
/**
* It logs the trace to a file
*
* @todo: implement a custom Exception class
* @package test.factory.trace
* @access public
*/

class FileTrace implements Trace {
   /**
   * It`s the file handler
   * @var handler
   * @access private
   */
   private $handler;
   /**
   * Is the file name
   * @var string
   * @access private
   */
   private $file;
   /**
   * debug
   * @var bool
   * @access private
   */
   private $debug;
   /**
   * The construnctor
   * it opens the file handler
   *
   * @param string the file name
   * @return void
   * @access public
   */
   public function __construct($file) {
      // a real FileTrace would need to obtain the filename somewhere
      if((!is_file($file)) or (!is_writable($file))) {
         throw new Exception("The file ".$file." is not writable,\n
         Or it dosent exist in ".__METHOD__." at ".__LINE__."!\n");
      }
      $this->handler = fopen($file, "a+");
   }
   /**
   * Sets the debug
   * @param bool debug
   * @return void
   * @access public
   */
   public function setDebug($debug) {
      $this->debug = $debug;
   }
   /**
   * It writes a debug message
   * only if debug is setted to true
   * @param string message
   * @return void
   * @throw Exception
   * @access public
   */
   public function debug($message) {
      if($this->debug) {
         // only print if debug is true
         fwrite($this->handler<;/span>, date("d-m-Y H:i:s")." DEBUG >>>> ".$message."\n");
      }
   }
   /**
   * It writes an error message
   *
   * @param string message
   * @return void
   * @throw Exception
   * @access public
   */
   public function error($message) {
      // always print out errors
      fwrite($this->handler, date("d-m-Y H:i:s")." ERROR >>>> ".$message."\n");
   }
   /**
   * Is the Destructor
   * just close the handle
   * @access public
   * return void
   */
   public function __destruct() {
      if($this->handler===true) {
         fclose($this->handler);
      }
   }
}
?>

I saved the file with the name FileTrace.php the same directory.

VI. Factory

CODE:
<?php
include_once('FileTrace.php');
include_once('StdoutTrace.php');

/**
* Is the factory
*
* @access public
* @package test.factory.trace
*/

class TraceFactory {
   /**
   * It trys to get a trace
   *
   * @access public
   * @return mixed Trace Interface implementation
   */
   public static function &getTrace($file='') {
      try {
         return new FileTrace($file);
      }
      catch (Exception $ex) {
         $t = new StdoutTrace();
         $t->error("Could not instantiate FileTrace: " + $ex->getMessage());
         return $t;
      }
   }
}
?>

Saved with the name TraceFactory.php 

VII. Some explanations

Before going further, I think it's time to explain what I did before. I tried to implement in PHP 5 a factory model taken from an example given in java.
In Part I, we wrote an interface containing three methods:

  • setDebug($debug), which will allow me to change the leve displayed by the trace (debug or error)
  • debug($message), i could display a debug message (of course if I did setDebug(true) in advance).
  • error($message), it will display an error message all the time (regardless of the value set for $ debug).

In the second part, as in the example which I followed, I implemented the Itrace interface two cases, FileTrace that will allow me to save the messages/errors to a text file named StdoutTrace and that will allow me to show these messages in the console (web page).
Mandatory the two new items will have to implement the interface methods presented in ITrace.
FileTrace, in the example followed by me, had to throw an exception in the constructor. We decided that if the file that I want to log messages into does not exist or it can't be written into it, i'll throw exception, but if everything is OK, i'll create the handler.

$this-> handler = fopen($file, "a+")

We decided to open the file in a+ (read/write, like the file pointer at the end of the file), although it was probably enough (and do not intend to read the file).
In addition to the following example, I wrote a destructor, but it was not necessary (PHPwill automatically terminate upon completion handler code execution?) and provided:

if ($this-> handler === true)

I think it's pointless (maybe something else is going in $this-> handler =fopen ($file, "a+") ?).
I decided to replace the attribute in PHP:

private java.io.PrintWriter pw

with $handler, and found that in PHP if you want to write something in a file is more intuitive and easier to remember.
Comparison:

pw = new java.io.PrintWriter (new java.io.FileWriter ("c:\trace.log")) (not very easy to retain this line)

with

$this-> handler = fopen($file, "a+");

the builders, or how to write (for example):

pw.println("DEBUG:" + message);
pw.flush() (??)

with

fwrite ($ this-> handler, data ("dmY H: i: s"). "DEBUG>>>>". $message. "\n");

But that is another question.
For greater flexibility, we decided to name the log file messages have to be passed in the constructor (like I want to go on linux and windows in the same manner, not using a default file name: c: \trace.log).
This brings direct changes to factory .
In contrast, In StdoutTrace things are pretty clear, just like in the example, except that the object name shown in the example (SystemTrace), I replaced it with StdoutTrace.

I will continue TraceFactory explanations.
Just as in this example, I declared the method as static, plus adding $file parameter, representing the file name in that you log messages.
I used a block try/catch to intercept the exception thrown by the manufacturer of FileTrace.
Perhaps the meaning of the example was changed when I decided to pass the file name where the log is done.
As a small translation, i'll try (try) to return a new instance of the object FileTrace, if i fail it (catch), initialized StdoutTrace that will surely go, having in this way the possibility to display error messages / debug.
In the next one to try and implement this example, although now it is quite intuitive.

VIII. An implementation

I wrote the RunTrace.php file:

CODE:
<?php
include_once('TraceFactory.php');

$filename = 'logger.log';

touch($filename);

$t = &TraceFactory::getTrace($filename);
$t->error("Test error!");
$t->setDebug(true);
$t->debug("Debug is true");

for($i=1;$i<10;$i++) {
   $t->debug("Tha lup :: ".$i);
}

unset($t);

$t = &TraceFactory::getTrace();
$t->error("Some test!");
$t->setDebug(true);
$t->debug("True Debug");

for($i=1;$i<10;$i++) {
   $t->debug("Za I :: " . $i);
}

$t->error("FOO IS BAR MUST DIE !!!");
?>

After execution, the console was the result:

Quote:

$ php runTrace.php

15-01-2005 14:42:24 ERROR >>>>0
15-01-2005 14:42:24 ERROR >>>>Some test!
15-01-2005 14:42:24 DEBUG >>>>True Debug
15-01-2005 14:42:24 DEBUG >>>>Za I :: 1
15-01-2005 14:42:24 DEBUG >>>>Za I :: 2
15-01-2005 14:42:24 DEBUG >>>>Za I :: 3
15-01-2005 14:42:24 DEBUG >>>>Za I :: 4
15-01-2005 14:42:24 DEBUG >>>>Za I :: 5
15-01-2005 14:42:24 DEBUG >>>>Za I :: 6
15-01-2005 14:42:24 DEBUG >>>>Za I :: 7
15-01-2005 14:42:24 DEBUG >>>>Za I :: 8
15-01-2005 14:42:24 DEBUG >>>>Za I :: 9
15-01-2005 14:42:24 ERROR >>>>FOO IS BAR MUST DIE !!!

And I have the file logger.log :

Quote:

15-01-2005 14:42:24 ERROR >>>> Test error!
15-01-2005 14:42:24 DEBUG >>>> Debug is true
15-01-2005 14:42:24 DEBUG >>>> Tha lup :: 1
15-01-2005 14:42:24 DEBUG >>>> Tha lup :: 2
15-01-2005 14:42:24 DEBUG >>>> Tha lup :: 3
15-01-2005 14:42:24 DEBUG >>>> Tha lup :: 4
15-01-2005 14:42:24 DEBUG >>>> Tha lup :: 5
15-01-2005 14:42:24 DEBUG >>>> Tha lup :: 6

15-01-2005 14:42:24 DEBUG >>>> Tha lup :: 7
15-01-2005 14:42:24 DEBUG >>>> Tha lup :: 8
15-01-2005 14:42:24 DEBUG >>>> Tha lup :: 9

If i comment the line:

touch($filename);

and delete the file logger.log, the result will be (OK, only the console, because the manufacturer of FileTrace will throw the exception because the file does not exist):

$ php runTrace.php

Quote:
15-01-2005 14:48:59 ERROR >>>>0
15-01-2005 14:48:59 ERROR >>>>Test error!
15-01-2005 14:48:59 DEBUG >>>>Debug is true
15-01-2005 14:48:59 DEBUG >>>>Tha lup :: 1
15-01-2005 14:48:59 DEBUG >>>>Tha lup :: 2
15-01-2005 14:48:59 DEBUG >>>>Tha lup :: 3
15-01-2005 14:48:59 DEBUG >>>>Tha lup :: 4
15-01-2005 14:48:59 DEBUG >>>>Tha lup :: 5
15-01-2005 14:48:59 DEBUG >>>>Tha lup :: 6
15-01-2005 14:48:59 DEBUG >>>>Tha lup :: 7
15-01-2005 14:48:59 DEBUG >>>>Tha lup :: 8
15-01-2005 14:48:59 DEBUG >>>>Tha lup :: 9
15-01-2005 14:48:59 ERROR >>>>0
15-01-2005 14:48:59 ERROR >>>>Some test!
15-01-2005 14:48:59 DEBUG >>>>True Debug
15-01-2005 14:48:59 DEBUG >>>>Za I :: 1
15-01-2005 14:48:59 DEBUG >>>>Za I :: 2
15-01-2005 14:48:59 DEBUG >>>>Za I :: 3
15-01-2005 14:48:59 DEBUG >>>>Za I :: 4
15-01-2005 14:48:59 DEBUG >>>>Za I :: 5
15-01-2005 14:48:59 DEBUG >>>>Za I :: 6
15-01-2005 14:48:59 DEBUG >>>>Za I :: 7
15-01-2005 14:48:59 DEBUG >>>>Za I :: 8
15-01-2005 14:48:59 DEBUG >>>>Za I :: 9
15-01-2005 14:48:59 ERROR >>>>FOO IS BAR MUST DIE !!!

However, i'm not satisfied with the written code, and more, passing the $file as a parameter in factory, and as a default the constructor FileTrace i got to far from the example from which we started.
I'll try to rewrite FileTrace and TraceFactory to reach the usefulness and the conclusions presented in the following example:

Quote:
Further, factory methods prove useful when you're not sure what concrete implementation of a class to instantiate. Instead, you can leave those details to the factory method.
In the above examples your program didn't know whether to create FileTrace or SystemTrace instances. Instead, you can program your objects to simply use Trace and leave the instantiation of the concrete implementation to a factory method.

IX. Some corrections

As I said at the end of last chapter, I decided to rewrite TraceFactory and FileTrace to be closer to the model followed.

FileTrace.php

CODE:
<?php
include_once('ITrace.php');
/**
* It logs the trace to a file
*
* @todo: implement a custom Exception class
* @package test.factory.trace
* @version 0.2
* @access public
*/
class FileTrace implements Trace {
   /**
   * It`s the file handler
   * @var handler
   * @access private
   */
   private $handler;

   /**
   * debug
   * @var bool
   * @access private
   */
   private $debug;

   /**
   * The construnctor
   * it opens the file handler
   *
   * @param string the file name
   * @return void
   * @access public
   */
   public function __construct() {
      $file = 'logger.log';
      if((!is_file($file)) or (!is_writable($file))) {
         throw new Exception("The file ".$file." is not writable,\nOr it
            dosent exist in: ".
            __METHOD__." at line: ".__LINE__."!");
      }
      $this->handler = fopen($file, "a");
   }

   /**
   * Sets the debug
   * @param bool debug
   * @return void
   * @access public
   */
   public function setDebug($debug) {
      $this->debug = $debug;
   }

   /**
   * It writes a debug message
   * only if debug is setted to true
   * @param string message
   * @return void
   * @access public
   */
   public function debug($message) {
      if($this->debug) {
         // only print if debug is true
         fwrite($this->handler, date("d-m-Y H:i:s")." DEBUG >>>> ".$message."\n");
      }
   }

   /**
   * It writes an error message
   *
   * @param string message
   * @return void
   * @access public
   */
   public function error($message) {
      // always print out errors
      fwrite($this->handler, date("d-m-Y H:i:s")." ERROR >>>> ".$message."\n");
   }

   /**
   * Is the Destructor
   * just close the handle
   * @access public
   * return void
   */
   public function __destruct() {
      fclose($this->handler);
   }
}
?>

TraceFactory.php

CODE:
<?php
/**
* Is the factory
*
* @version 0.2
* @access public
* @package test.factory.trace
*/

class TraceFactory {
   /**
   * It trys to get a trace
   *
   * @access public
   * @return mixed Trace Interface implementation
   */
   public static function &getTrace() {
      try {
         include_once('FileTrace.php');
         return new FileTrace();
      }
      catch (Exception $ex) {
         include_once('StdoutTrace.php');
         $t = new StdoutTrace();
         $t->error("Could not instantiate FileTrace:\n".$ex->getMessage());
         return $t;
      }
   }
}
?>

X. Other explanations

I tried to get as close as posible to the example I followed.
Rather, the manufacturer of FileTrace could be rewritten as:

CODE:
<?php
function __construct() {
   $file = 'logger.log';
   $this->handler = @fopen($file, "a");
   if($this->handler===false) {
      throw new Exception("Cannot create the file hanled!");
   }
}
?>

However, on windows would be more difficult to test, but there should be no concerns about the fact that I could not create the file logger.log. On linux, taking into account the permissions that must be set for the working directory should still be possible.

XI. Another implementation

I rewrote the mini runTrace.php test as follows:

CODE:
<?php
include_once('TraceFactory.php');
$t = &TraceFactory::getTrace();
$t->error("O eroare de test!");
$t->setDebug(true);
$t->debug();
Publishing date: 08-02-2011 - Copyright © Aurelian   
Click here if you want to see other articles by the same author

There is a similar article, click here for list.

There are no comments on this article. Be the first to say your opinion.

Add a comment on this article (members only - login on the site):
Put your ad here