Page 1 of 3
Modularity in PHP
Posted: Mon Jan 30, 2006 4:22 pm
by Gambler
How do you achieve modularity of your applications? Do you use some kind of wrapper for include_once or class autoloader? What about directory structure and class names? Table names, DB use?
Posted: Mon Jan 30, 2006 4:56 pm
by Chris Corbyn
__autoload()
As for path names I'd go with whatever makes sense to you.... I usually just have /app/classes/classname.class.php /app/interfaces/classname.interface.php and /app/templates/name.tpl.php

That's purely a personal preferecne though... i haven't researched it in any way, it just seems logical.
Posted: Mon Jan 30, 2006 4:59 pm
by josh
All path names are set with define(), that would be a start
Are you talking about allowing plugins? Just have a plugin loader class that expects your plugins to have a "main" class that adhere's to a specific api, let the plugin's author worry about the internals of their plugins as long as you can interface it ok. You would obviously need to expand upon this when you want to allow the plugin to start interfacing your application directly instead of the other way around but you can get pretty creative with that one way communication
You can also set up a class that the plugins can interface to talk to other plugins, etc... It will just take a lot of storyboarding / planning to get it just right the first time around.
Re: Modularity in PHP
Posted: Mon Jan 30, 2006 5:10 pm
by Christopher
A lot of big questions there. Probably a long thread to cover each. It reminds me of the old saying: How do I get to Carnegie Hall? Practice, practice, practice.
Gambler wrote:How do you achieve modularity of your applications?
There are lots of answers to this. My general opinion (others will disagree) is that the state of the art is to use many small classes to build up you application. This supports DRY and is the key to making things testable which is central to Agile methodologies.
Gambler wrote:Do you use some kind of wrapper for include_once or class autoloader?
You can use the __autoload function, but you might just want to include/create your object directly until you actually have a complexity problem. There are many ways to solve this and get Lazy Load that __autoload gives you. Probably the most common is to dispatch everything that PHP programmers would normally consider a "page" (usually refered to as an action) as an object using the Command pattern. This is how most controller based architectures work. The Front Controller is probably the most commonly used approach for this. All this usually heads toward a PHP spin on MVC which is a very long discussion in itself.
Gambler wrote:What about directory structure and class names?
I try to keep all code and templates out of HTML space with only the controller scripts, image, javascript and CSS in the public directory. Naming is personal and pretty trivial it ends up. There is much more agreement than all the flamewars would indicate. The PHP site has some naming conventions as I recall -- they are probably fine.
Gambler wrote:Table names, DB use?
Tables names like all naming is up to you and not worth the litany of opinions. For DB use (and I assume you mean implementation, not server type) the most important thing is that there is separation between you data layer and your presentation layer. If you achieve that you are 90% of the way to a solid architecture. Beyond that the question becomes what kind of functionality you need. A basic Connection object is the norm. It can return a dumb Record Set or smarter Active Record. Or better would be to create Gateway classes for your data access. Table Data Gateway is simple and straightforward. If you don't control the database and it changes regularly then you might want to implement a Data/OR Mapper to translate between your objects and the database schema to insulate yourself from those changes.
Posted: Mon Jan 30, 2006 5:16 pm
by John Cartwright
I usually run some kind of database install script, where a where an admin can dynamically control what plugins are to be loaded.
It certainly isn't required to get an efficient plug in system, but it really comes down to personal preference (as long as its not stupidly complex)
Posted: Tue Jan 31, 2006 6:28 am
by Gambler
__autoload()
Autoload itself isn't modular. You can declear it only once.
Are you talking about allowing plugins?
Yes and no. Word "plugins" assumes that there is a core system, which barkes the rules. Also, it assumes that other classes are written specificly for that core system.
Posted: Tue Jan 31, 2006 7:41 am
by Jenk
Gambler wrote:__autoload()
Autoload itself isn't modular. You can declear it only once.
Are you talking about allowing plugins?
Yes and no. Word "plugins" assumes that there is a core system, which barkes the rules. Also, it assumes that other classes are written specificly for that core system.
Code: Select all
<?php
if ((function_exists('__autoload')) === FALSE) {
function __autoload($class)
{
include_once($class . '.php');
}
}
?>
Posted: Tue Jan 31, 2006 7:49 am
by CoderGoblin
Table names, DB...
Rather than go into PHP I would like to point out that database table names should all be lower case with the name as plural, as descriptive as possible. For instance rather than "UserName" use "user_names". Don't be tempted by abbreviations as you are unlikely to remember them a year down the line. 'uname' is one I have seen before. There are some useful guidelines as far as databases naming conventions/good practice but I cannot think of any links off-hand and I have never stored them.
Key thing with anything like this is build everything on the assumption that someone else may need to use your code/structures. Keep it as descriptive as possible while still being simple.
Posted: Tue Jan 31, 2006 7:53 am
by Gambler
Jenk, this doesn't achieve anything, because other __autoload might use completely different coventions. So it would be defined, but your script would break anyway.
Currently, I'm using load().
Code: Select all
<?php
function load(){
$args = func_get_args();
$result = TRUE;
foreach ($args as $name) {
$file = 'tools/'.$name.'.php';
$result = $result && (bool)include_once($file);
}
return $result;
}
?>
Not the best way either.
The C.J. Code Modularity Project
Posted: Tue Jan 31, 2006 8:12 am
by cj5
Well, I start with 1) a DB table, 2) two PHP classes (one for frontend, one for admin), and a template.
1) The tables always have several columns in common:
a) 'id' The primary key (always available, never excluded)
b) Depending on the situation, the table will include a name/title field, which is given 'title'
this is usually for the purpose of naming whatever it is we are storing.
c) If necessary (when making one-to-one relationship), I include a ID column for an external table relation connection.
d) In considering relational data, I will sometimes include two more tables for one-to-many relationships (so that makes 3 tables; one
this data, one for the relational data, and the connector)
e) As a standard, always include an 'insert_stamp' and 'update_stamp' column, for time logging
2) PHP classes for data manipulation and output:
a) Frontend class:
i) Include all SQL methods for fetching any data I need
ii) Data formatting methods (takes data arrays, and gets them ready for the template)
iii) Establish all page, DB, server, and template information through class variables (this will allow you to plug these classes into your site anywhere, without having to change links, table, or path information)
b) Backend/Admin class (extends the frontend class):
i) Data manipulation methods (insert, updates, etc... for add, edit, delete...)
ii) File uploading processing and methods
iii) Form validation and processing
3) Template: (pretty self-explanatory)
Most of this comes from my information management background, and the fact that I am very OC about my code, when it comes to getting it organized, and keeping it that way. I also do consulting for a fee. =)
Posted: Tue Jan 31, 2006 8:50 am
by Jenk
Gambler wrote:Jenk, this doesn't achieve anything, because other __autoload might use completely different coventions. So it would be defined, but your script would break anyway.
Currently, I'm using load().
Code: Select all
<?php
function load(){
$args = func_get_args();
$result = TRUE;
foreach ($args as $name) {
$file = 'tools/'.$name.'.php';
$result = $result && (bool)include_once($file);
}
return $result;
}
?>
Not the best way either.
You misunderstand the purpose of __autoload..
Would fail, no class definition found..
Because many developers separate their classes into files of their own, usually sharing the same name as the class definition within, the php bod's decided to try and take a leaf out of Java (and other's) book and allow for the use of auto-inclusion. This could not be fully implemented as it is a late addition, thus so we now have the ability to switch this feature "on" by defining the __autoload function.
Code: Select all
<?php
if ((function_exists('__autoload')) === FALSE) {
function __autoload ($classname)
{
include_once($_SERVER['DOCUMENT_ROOT'] . 'includes/' . $classname . '.inc.php');
}
}
$class = new Class;
?>
Would not fail, providing you have the class deifnition for Class in a file called Class.in.php in the /doc-root/includes/ directory.
All the if is for is so you can nest the __autoload function within the various files that you might need to include in your project and not get function already defined errors.
Posted: Tue Jan 31, 2006 9:36 am
by Gambler
Okay, let me give an example.
You have:
Code: Select all
<?php
if ((function_exists('__autoload')) === FALSE) {
function __autoload ($classname)
{
include_once($_SERVER['DOCUMENT_ROOT'] . 'includes/' . $classname . '.inc.php');
}
}
?>
I have:
Code: Select all
<?php
if ((function_exists('__autoload')) === FALSE) {
function __autoload ($classname)
{
include_once('tools/'.$classname.'.php');
}
}
?>
Now I want to use your classes (modules), which rely on __autolod(). Ta-dam! Conflict. Thus, code with __autoload() is not modular.
Posted: Tue Jan 31, 2006 10:37 am
by Jenk
That is a problem not just limited to __autoload() and is infact a problem that will never be solved.
My classes use the pseudo-global $MY_SUPER_GLOBAL; to gain and pass through various details that are available to the entire application..
Yours uses $MY_GLOBAL_CONFIG; .. Ta-da! Conflict.
Atleast with __autoload() you can separate this even further in two ways..
__autoload.php (or prepend to a generic 'config' file that many applications use):
Code: Select all
<?php
if ((function_exists('__autoload')) === FALSE) {
function __autoload($class) {
include_once("includes/{$class}.inc.php");
}
}
?>
Then in any other page:
Code: Select all
<?php
include '__autoload.php'; //or swap for your generic config file which could have this in.
?>
OR, set your include_path to also search your includes directory, and not use any path in the autoload function, only the filename. File extension will just need to be arbitrary.
Posted: Tue Jan 31, 2006 10:59 am
by Christopher
Gambler wrote:Okay, let me give an example.
Now I want to use your classes (modules), which rely on __autolod(). Ta-dam! Conflict. Thus, code with __autoload() is not modular.
As I said, you might want to start out just including files directly with the path specified. If you don't have a complexity problem managing the paths then that is the most straightforwared. A reasonable alternative to __autoload() is something like this:
Code: Select all
$path .= PATH_SEPARATOR . $_SERVER['DOCUMENT_ROOT'] . 'includes/' ;
$path .= PATH_SEPARATOR . 'tools/' ;
set_include_path(get_include_path() . $path);
// and then
include_once('Classname.php');
$obj = new Classname()
You can also you PEAR style naming and covert underscores to forward slashes in your __autoload() but you will need to be careful of capitalization.
Posted: Tue Jan 31, 2006 11:12 am
by Weirdan
CoderGoblin wrote:
I would like to point out that database table names should all be lower case with the name as plural
That's clearly a matter of preference. For example, IDEF1X suggests that you name your entities (tables) using
singular nouns written in upper case. Indeed, "SELECT `user`.`name` FROM ... " looks more natural to me than "SELECT `users`.`name` FROM ..." (I don't like to use upper case for table names).