OOP design (pattern)

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

ghost007
Forum Commoner
Posts: 49
Joined: Sat Nov 22, 2003 10:10 am

OOP design (pattern)

Post by ghost007 »

Hi all, hope you all had a very nice christmas and that 2004 finally may be the year where all your great projects will be realized :mrgreen:

As I started learning a bit more about OOP almost one month ago I have red a lot about this subject and come accross a lot of different example scripts and frameworks.

One of those (phpframe) kept my attention because it did approximately what I want.

I hacked a bit the original idea and came up with something that works. But now I'm wondering if this is a good way to go.

Well thx if you red until here and hopefully you will even read the rest.

[File: class.backend.php] the backend class will be included in all other classes such as my database class to be able to use the error functions and to use the config vars.

Code: Select all

<?php
class Config
{
	var $error_reporting = 1;
	var $dbhost = "localhost"; //MySQL Database Server
	var $dbuser = "root"; //MySQL Database User
	var $dbpass = "XXX"; //MySQL Database Password
	var $dbname = "XXX"; //MySQL Database
//other global vars I want to use in all scripts so all my config vars stay
//together in one file.
}
class Object extends Config
{

    function Object()
    {
        // Grab our arguments
        $args = func_get_args();
        // Register our destructor
        register_shutdown_function(array(&$this, '__destruct'));
        // Call our contructor
        call_user_func_array(array(&$this, '__construct'), $args[0]);
    }

   
   /**
    * Abstract Constructor
    */
    function __construct()
    {
        // Do nothing
    }
    /**
    * Abstract Destructor
    */
    function __destruct()
    {
        // Do nothing
    }

}

class backend extends Object{
	
	function createObject($_classname, $_params='')
    {
	//echo $_classname;exit;
    	// include file if it's not already been included
        if (!class_exists($_classname)) require_once("class.".$_classname.".php");
        if (!is_array($_params)) $object = new $_classname;
        else $object =& new $_classname($_params);
        
        // Assign a reference to the application object to the class so App is always accesable 
        $object->front =& $this;
        return $object;
    }

//I have some other functions in here such as error function, ...
}
?>
[file: class.frontend.php] will be used to construct some classes by default and have general functions for pages that output to the browser.

Code: Select all

<?php

require_once("class.backend.php");

class frontend extends backend{
	var $start;
		
	function __construct()	{

		$this->datab = $this->createObject('mysql');
		$this->tpl = $this->createObject('template');

	}
//some other functions in here used for example by index.php
}

?>
So the idea is that I:
> construct my mysql and template class by default
> can construct new classes when needed (e.g. class.users.php will be loaded when authentication is necessary).
> all my global vars are in the same file (withou using "global" because insecure and without using "Constants" because slow).
> can use the same framework for all my projects => just construct the classes needed.

Plz note that I'm only learning OOP so if this makes no sense it's now that I should know it so just go ahead and burn me to the ground. (with appropriate explanation why if possible :) ).

thx if you red this whole junk of code and naturally thx 1M times if you post your comments.

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

Post by Nay »

Code: Select all

function __construct()
Is it my bad memory or that's PHP5?

-Nay
ghost007
Forum Commoner
Posts: 49
Joined: Sat Nov 22, 2003 10:10 am

Post by ghost007 »

hi Nay,

thx for the hyper fast reply :).

yeah it's a nice trick hu. I got this from the phpframe script.

It's the class object that emulates the ___construct function as it will be in PHP 5.

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

Post by Nay »

mm right......

it was a bit odd since I never declare a function starting with ___. I'd probably won't be getting much of OOP until PHP5's 'really' out. Then I'd get a book on OOP and PHP5. By the time my slow brain learns it, PHP5 should be on most servers.

Or maybe even PHP7 by the time I learn OOP in PHP =\

-Nay
User avatar
lazy_yogi
Forum Contributor
Posts: 243
Joined: Fri Jan 24, 2003 3:27 am

Post by lazy_yogi »

Excellent Ghost!

Very impressed with your object class and how it makes converting to php5 such a breeze.
I user 'register_shutdown_function' but didn't think to use 'call_user_func_array' for the constructor. Nice.

Also very impressed with your factory (though not sure why you called it 'backend' =P)

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

Post by Nay »

I was re-reading that. What's the & 8O?

Code: Select all

&$this, '__construct
-Nay
User avatar
lazy_yogi
Forum Contributor
Posts: 243
Joined: Fri Jan 24, 2003 3:27 am

Post by lazy_yogi »

Hey Siech.

Just tried it and it works like a dream
Though, I put the factory method (createObject) in the Object class.
Not that I'm saying it is a better way, I just find it simpler.

Mind if I get a look at your error/error handling stuff ?
Also, if you don't mind, could I get a link to some of these scripts, especially phpframe.

Cheers,
Eli
User avatar
Weirdan
Moderator
Posts: 5978
Joined: Mon Nov 03, 2003 6:13 pm
Location: Odessa, Ukraine

Post by Weirdan »

Nay wrote:I was re-reading that. What's the & 8O?
http://www.php.net/manual/en/language.r ... s.pass.php
ghost007
Forum Commoner
Posts: 49
Joined: Sat Nov 22, 2003 10:10 am

hi

Post by ghost007 »

thx for all the positive comments even of most of them go to the programer of phpframe :roll:

you can find the beta version of PHPframe here:
http://www.jerrett.net/projects/phpframe/

the whole code for the constructor is taken from this script. I removed what I did not understand and don't use his other classes as I found it a strange way to group all your mysql queries in a separate page. But if you want to comment a bit more this code I'm more than interested to get it better, certainly now that you confirm that his way is the right way.

the error routine uses a simple redirect function and allows me to set a param if I want debug info to be shown:

Code: Select all

<?php
	function error_page($line,$file,$err,$err_title = 0,$page = 0,$webID = 0)
	{
		if ($this->error_reporting == 1 && $file != '0') {
			echo "Mysql error:<br>".mysql_error()."<br>On line: ".$line."<br>In File: ".$file;
			exit;
		}else {
			if ($file != '0') mail($this->adminmail,"mysql error on ghost007","On line: ".$line."<br>On page: ".$file);
			$url = $this->error_url . "?err=" . $err . "&tit=" . $err_title . "&page=" . $page . "&webid=" . $webID;
			$this->redirect($url);
		}
	}

	function redirect ($loc)
	{
	//echo "<meta http-equiv=refresh content=1;URL=$loc>";
		if (headers_sent())
			echo "\n<script language='JavaScript'><!--\nwindow.location='$loc'\n//--></script>\n";
		else
			header("Location: $loc");
		exit();
	} 


?>
the error url redirects to a php page that uses the get vars to define the error msg to show. I do not use this function for error msg in a form where they are shown on the same page.

cheers

Siech
User avatar
lazy_yogi
Forum Contributor
Posts: 243
Joined: Fri Jan 24, 2003 3:27 am

Post by lazy_yogi »

OOP error handling is immensely better than that in php and other proceedural error handling

I'd love to be able to emulate the exceptions in OOP.
I imagine I'd have to create a singleton class though.

For example:

Code: Select all

class Exceptions {
   function throw($exceptions){
      $this->exceptions[] = $exceptioin;
   }
   function hasExceptions(){
      return count($this->exceptions) > 0;
   }
}

class Object { 
   function Object() {
      // if singleton exception class not instantiated, instantiate it
      // as a global variable (not as an instance of this class)
   }
}
Then to use it:

Code: Select all

class blah{
    function somefunction( {

       executeSomething();  // or $this->executeSomething
       if $Exception->hasExceptions() {
           // handle the exceptions
       }
    }
}

If anyone has created a singleton class before in php, it'd be great to see it.

Cheers,
Eli
ghost007
Forum Commoner
Posts: 49
Joined: Sat Nov 22, 2003 10:10 am

hi yogi

Post by ghost007 »

have you checked out the phpframe script? what do you think about it?

For the error class I will post some more details on how I handle the errors of my forms as this is almost as your example.

The idea was to include backend php in my private classes and only use frontend in the pages that will output info to the user.

e.g. index php will include frontend.php and use createobject when it needs for example the user.class.php also.

in the user.class.php I will include only the backend.php and include other classes that I need separately e.g. include mysql.class.php also because I connect to DB.

I thought this would make the code more portable as this was my only objective by using this structure.

thx for all comments (advantages/disadvantages) on this approach.

PS: I red the info on patterns for 10 times now on phppattern.com but still can't see these patterns in my code. Some more links to more basic tutorials on patterns would be more than welcome. thx

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

Post by Nay »

Man, your obbessed lol :P.

I read........I confused.........I run away.....

mMm.......now If only I can stop doing that with OOP.

-Nay
User avatar
lazy_yogi
Forum Contributor
Posts: 243
Joined: Fri Jan 24, 2003 3:27 am

Post by lazy_yogi »

design patterns :
http://www.dofactory.com/Patterns/Patterns.aspx

the creation of abstract objects is a perfect example of the abstract factory pattern :
http://www.dofactory.com/Patterns/PatternAbstract.aspx

Under 'Sample code in C#' click on 'Show code' and read that code.
You will need to read it carefully and probably a few times to understand it fully.


The end of that section of code says

Code: Select all

AbstractFactory factory1 = new ConcreteFactory1();
Environment e1 = new Environment( factory1 );
which says:
1. create a factory object - factory1 - which is a factory type (similar to your createObject that creates objects)
2. create an environment (with argument a factory object)
now look in the Enviroment class.
the constructor has

Code: Select all

AbstractProductB = factory.CreateProductB();
which is an example of a class htat produces an object productB.

So essentially, it produces objects without you having to do any other work other than say 'factory.CreateProductB()' similar to how you don't have to do any other work other than 'createObject('objectname')'

called 'factory' because it produces things - in this case, objects.

# ------------------ END OF DESIGN PATTERN STUFF ------------------- #

Your redirect is excellent. well done with it.


I've looked briefly into the rest of phpframe.
From what I've seen, that is the most useful part - what you took out.

I'd be pretty damn happy with that and a way to do exception handline if its possible to emulate in php. Current error handling is a waste of offort in my opintion .. better to just use die() and wait for php5 .. unless it can be emulated somehow like __construct and __destruct has been done here.

I dun like the 'extendedApp' classes constructor. I perfer to instantiate all a classes objects inside each class. It's only an extra line per object with the app framework, and you can see what objects are in the class without having to check the inherited 'app' object.

His database class isn't bad. But I perfer mine.

His Resonse class looks interesting .. but too busy to look at it in more depth.

I put the config class in a seperate file so users can modify configuration info without seeing or needing to access the rest of the object class (the internal workings of classes should be kept hidden in OOP - its called encapsulation). And I put the createObject function in the Object class.
So from your first post, I have a config class in one file and an baseObject class which is your object class with createObject method put in there. And I inherit from baseObject in all other classes

ok .... thats my 2 cents for wot its worth.
Sorry for the length of the post

Cheers,
Eli
ghost007
Forum Commoner
Posts: 49
Joined: Sat Nov 22, 2003 10:10 am

Post by ghost007 »

Great answer Eli thx!

I will need some time to read trough the info about objects in C as I have no knowledge about this language at all. but from what you explaned in your post my "basic" knowledge of php should be enough to understand this.

It is also nice to see that a course in OOP is almost worth 2000$ 8O so even if I don't make any money out of this, at least the knowledge is worth something :)

You made a point also that the code is more transparant if u use the "createobject" in all classes where you need it. for me it was more because I'm lazy so it seemed nice to instantiate as much classes by default as possible :).

I don't use his other classes neither as I already had a solution for most of them. maybe you may be interested to check out some of the work of phpGuru: http://www.phpguru.org/ who has a very nice (IMHO) template class that is understandable and easy to adapt to your needs.

So thx once more for your very worthy respons.

cheers
Siech

PS: Nay I'm sorry my post confuse you. As you will probably already know my mother tongue is not english.
PPS: plz come back, It was not personal :P
Nay
Forum Regular
Posts: 951
Joined: Fri Jun 20, 2003 11:03 am
Location: Brisbane, Australia

Post by Nay »

Hey ghost........you mean that was you on ICQ? lol.......heh.....

mm......i think i was high on 'awake-too-much', man, thoses stuff are addictive ;)

-Nay
Post Reply