Developing a PHP5 only app

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

Post Reply
ben.artiss
Forum Contributor
Posts: 116
Joined: Fri Jan 23, 2009 3:04 pm

Developing a PHP5 only app

Post by ben.artiss »

Hi all,

I've been making attempts at building my own framework and CMS for quite some time, and have settled into a coding standard that is only supported by PHP 5+.

There's nothing out of the ordinary about the system, but I've never seen other frameworks or CMS's using functions as though they were variables. My question is, is the following example an acceptable coding standard to have if I am to continue developing in this way?

Code: Select all

function &app($class = NULL, $alias = NULL)
{
	static $app;

	if (empty($app))
	{
		$app = new stdClass();
	}

	if ( ! empty($class))
	{
		$key = ($alias) ? $alias : $class;

		if ( ! isset($app->{$key}))
		{
			$app->{$key} =& load_class($class);
		}

		return $app->{$key};
	}

	return $app;
}

$cfg_item = app()->cfg->get('some_config_item');
I gave it a quick test in PHP 4 just to see what error it would give, which was "unexpected T_OBJECT_OPERATOR". I really like working this way because you are always accessing the same object no matter where you use it, so you can even create alias (shortcut) functions, e.g.

Code: Select all

function &cfg()
{
	return app('config', 'cfg');
}

$cfg_item = cfg()->get('some_config_item');
Do you think this is an acceptable and efficient way to be writing code? My main reason for asking is because I don't really see anyone else doing it, but this might be because I've not looked far and wide! :)
User avatar
getmizanur
Forum Commoner
Posts: 71
Joined: Sun Sep 06, 2009 12:28 pm

Re: Developing a PHP5 only app

Post by getmizanur »

your code is elegant however the question is why do you want to do it like that when you have keyword 'new' to create a instance of a class. once a class is instantiated, you can access the encapsulated variables and functions using php object operator. in my own opinion there is no need to reinvent the wheel when you can make do with php reserved keywords.

this is not to say you are wrong however i like to exhaust all php built in options before i create my own.

so if you feel this is right then go ahead and do it.
ben.artiss
Forum Contributor
Posts: 116
Joined: Fri Jan 23, 2009 3:04 pm

Re: Developing a PHP5 only app

Post by ben.artiss »

That's good to hear! :) I was hoping nobody would come back with major criticisms so I'll carry on doing it this way.

I do eventually make use of the 'new' keyword to instantiate classes but I'm doing that in the load_class function to make sure I only ever instantiate it once (kind of the singleton approach but not quite).

Code: Select all

function &load_class($class)
{
	static $classes;

	if ( ! empty($classes) && isset($classes[$class]))
	{
		return $classes[$class];
	}

	if ( ! class_exists($class))
	{
		$classes[$class] = NULL;
		return FALSE;
	}

	$classes[$class] = new $class();

	return $classes[$class];
}
Thanks for the reply getmizanur
User avatar
getmizanur
Forum Commoner
Posts: 71
Joined: Sun Sep 06, 2009 12:28 pm

Re: Developing a PHP5 only app

Post by getmizanur »

cool. good work
User avatar
Zyxist
Forum Contributor
Posts: 104
Joined: Sun Jan 14, 2007 10:44 am
Location: Cracow, Poland

Re: Developing a PHP5 only app

Post by Zyxist »

In PHP5, you should not use references for objects, because object variables are already references.

Furthermore, I guarantee you that you will have trouble in the future, if you keep using such inventions, like load_class() or app(). Your style has very little to do with object-oriented programming. I'd call it class-oriented programming and this is not the way you should follow. Do not use "magic object accessors" (especially made with functions). Create an object explicitely or with a factory. If you need it somewhere, inject it through the constructor or the setter method.
User avatar
AbraCadaver
DevNet Master
Posts: 2572
Joined: Mon Feb 24, 2003 10:12 am
Location: The Republic of Texas
Contact:

Re: Developing a PHP5 only app

Post by AbraCadaver »

I would have to agree that this is very strange. Using stand-alone functions to create objects. I think you would be better served by learning some of the design patterns and using them, especially if others will need to work with your code. You are using classes/objects but you have de-constructed the OOP Registry pattern into a function.
mysql_function(): WARNING: This extension is deprecated as of PHP 5.5.0, and will be removed in the future. Instead, the MySQLi or PDO_MySQLextension should be used. See also MySQL: choosing an API guide and related FAQ for more information.
User avatar
Weirdan
Moderator
Posts: 5978
Joined: Mon Nov 03, 2003 6:13 pm
Location: Odessa, Ukraine

Re: Developing a PHP5 only app

Post by Weirdan »

I would have to agree that this is very strange. Using stand-alone functions to create objects.
Is it any stranger than using static methods to create objects?
I think you would be better served by learning some of the design patterns and using them, especially if others will need to work with your code.
Singleton registry is still considered viable pattern by many, and this is what we see here, disguised as a function. Total dependency injection is a whole other level of complexity - hardly necessary in every single application.

What I don't like about code here is that it's using static variables - if it was instead just an interface to classic registry I wouldn't have any objections. In fact I use similar solution for logging:

Code: Select all

logger()->err('Oops, you cannot do this'); 
Behind the scenes it fetches logger object configured in bootstrap and returns it. All the dirty work like message routing, formatting and storing is then done by that logger object (Zend_Log instance).
User avatar
Zyxist
Forum Contributor
Posts: 104
Joined: Sun Jan 14, 2007 10:44 am
Location: Cracow, Poland

Re: Developing a PHP5 only app

Post by Zyxist »

Functions cannot be autoloaded. Using exotic file loading techniques will cause you trouble, when you want to integrate your code with some third party library. Dependency injection is just passing the necessary dependencies via constructors and setters. Nobody forces you to use dependency injection containers :). Maybe sometimes it requires me to write two, three more lines, but even after a year it is more readable, and most of all: I can use the code in any other project without any problems. Who says that the piece from a small application wouldn't be useful in the bigger one?
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Re: Developing a PHP5 only app

Post by Jenk »

Just to chime in that I dislike statics/globals/global functions. They are an implicit dependency that is not visible on the objects interface. In Weirdan's example, if an object uses logger() I would strongly encourage that the object is injected as an explicit dependency :)
User avatar
Weirdan
Moderator
Posts: 5978
Joined: Mon Nov 03, 2003 6:13 pm
Location: Odessa, Ukraine

Re: Developing a PHP5 only app

Post by Weirdan »

Zyxist wrote:Functions cannot be autoloaded.
Fair point.
Using exotic file loading techniques will cause you trouble, when you want to integrate your code with some third party library.
Since when require_once has became exotic? And how exactly it could cause trouble?
Who says that the piece from a small application wouldn't be useful in the bigger one?
That's the developer's call - and I say the code using straight logger() calls can't be useful in other applications. Reusable parts have this service injected in a classical way:

Code: Select all

$service = new SomeService;
$service->setLogger(logger());
User avatar
Zyxist
Forum Contributor
Posts: 104
Joined: Sun Jan 14, 2007 10:44 am
Location: Cracow, Poland

Re: Developing a PHP5 only app

Post by Zyxist »

Since PHP introduced more transparent loading techniques. Imagine that I have an application, where I'm using autoloaders to load the files and I want to use your code that uses require_once. Now, especially for that I must introduce yet another way to load files, and I must learn the structure of your code to get to know, how to load it. A couple of months later I want to improve the loading on the production server to increase the performance and I can't, because your code is loaded in a completely different way and it is not scalable. Library loading should not be a part of the application. You should configure it at the very beginning and forget about it in the rest of the application - this is the only possible way to make it scalable.

This works in the opposite side, too. You have your own code, and now you want to introduce some new library which uses another loading technique. What now? This is a real pain in PHP - you waste time trying to integrate everything, your server wastes time to handle several different loading approaches.
ben.artiss
Forum Contributor
Posts: 116
Joined: Fri Jan 23, 2009 3:04 pm

Re: Developing a PHP5 only app

Post by ben.artiss »

Interestingly, I've been using Drupal a bit recently and have seen the odd instance where they've used the function()->method() approach, but reading what everyone's said it seems that the general conclusion is not to carry on with what I'm doing; to which I agree for the most part. I agree that having a shortcut function for each library is not very scalable (I didn't notice at the time), but I can't really see the problem with faking a singleton approach using a function such as app(). If loading and using core libraries is limited to a single function, surely this isn't restrictive? E.g. if you wanted to single out a specific library, you could simply do:

Code: Select all

$db =& app('db');

// Or you could use:
$db =& load_class('db');
The reason I started to use the app() function was to introduce a bit of a standard way of doing things. But no matter which way you use the library you end up using the same instance so long as you assign it to a variable by reference:

Code: Select all

$db =& app('db');
$db->query('...');

app('db')->query('...');
app()->db->query('...');
All of those examples use the same instance. Am I alone in thinking that's efficient, or am I not understanding something?
User avatar
Zyxist
Forum Contributor
Posts: 104
Joined: Sun Jan 14, 2007 10:44 am
Location: Cracow, Poland

Re: Developing a PHP5 only app

Post by Zyxist »

There is one more problem with singletons and such functions - automated testing. Unit tests are hard to write for singleton-based code. For function-based singletons with static variables I don't even think it is possible unless we use some process isolation (how to reset the reference?). Note that such applications as Drupal were originally developed by people who did not care about testing, how it will work in the future etc. Later, the code and user base was too large to fix it*. And with bigger projects that last year, or two, magic side effects and testing issues become a serious problem.

* - actually, the age of the code is clearly visible here:

Code: Select all

$db =& app('db');
When working with PHP5 objects, you forget about the reference sign.
ben.artiss
Forum Contributor
Posts: 116
Joined: Fri Jan 23, 2009 3:04 pm

Re: Developing a PHP5 only app

Post by ben.artiss »

Ahh I didn't realise the =& wasn't needed in PHP5. I was also looking into TDD earlier on; I can see what you mean about it being hard to test. I might keep some of the fundamental ideas of this system and rewrite it in a bit more of a scalable way. Shame.. I was really enjoying the way it was all going! :)

Thanks for the replies.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: Developing a PHP5 only app

Post by Christopher »

ben.artiss wrote:

Code: Select all

$db =& app('db');
$db->query('...');

app('db')->query('...');
app()->db->query('...');
All of those examples use the same instance. Am I alone in thinking that's efficient, or am I not understanding something?
One could say that if this makes things easy and fast for you to develop the set of applications that you develop then go wild. One could also say that the something your are "not understanding" is the last 30-40 years of software design theory.

A general answer to the above code is that while they all do the same thing the open you up to different side effects, help or limit your ability to write tests, hinders you ability to make changes without workarounds, etc. Programmers usually think their code looks reasonable because they have agreed to every trade-off made while designing that code. Usually several of those trade-offs are considered bad practice for very good (but often counter intuitive) reasons.

You are asking a key design question for PHP programmers. We start with the good premise and practice of using objects in object-y ways. So you want a database connection object to submit queries to the database:

Code: Select all

$resultObj = $dbObj->query('SELECT...');
So now the question becomes: How do I get that $dbObj? You could do:

Code: Select all

$dbObj = new My_Db_Class($configData);
But then the question is: How do I get that $configData? And so on.

There are a number of answers to these basic PHP application design question. You want to create a magic God object that contains all this information inside so everything just works. It is the first place PHP programmers go in OO. It has a bunch of problems, as people have mentioned above. There are a number of proven patterns that can improve things, like Registries and Dependency Injection, but they require some upfront work to save time later -- and do not cause the problems inherent in static, global solutions.

But this is a very big subject...
(#10850)
Post Reply