Page 1 of 1
Developing a PHP5 only app
Posted: Sat Jun 11, 2011 11:32 am
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!

Re: Developing a PHP5 only app
Posted: Sat Jun 11, 2011 1:20 pm
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.
Re: Developing a PHP5 only app
Posted: Sun Jun 12, 2011 12:54 pm
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
Re: Developing a PHP5 only app
Posted: Sun Jun 12, 2011 1:52 pm
by getmizanur
cool. good work
Re: Developing a PHP5 only app
Posted: Fri Jun 17, 2011 2:35 am
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.
Re: Developing a PHP5 only app
Posted: Fri Jun 17, 2011 11:04 am
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.
Re: Developing a PHP5 only app
Posted: Fri Jun 17, 2011 7:37 pm
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).
Re: Developing a PHP5 only app
Posted: Mon Jun 20, 2011 12:49 am
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?
Re: Developing a PHP5 only app
Posted: Mon Jun 20, 2011 5:55 am
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

Re: Developing a PHP5 only app
Posted: Mon Jun 20, 2011 7:35 am
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());
Re: Developing a PHP5 only app
Posted: Thu Jun 23, 2011 3:22 am
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.
Re: Developing a PHP5 only app
Posted: Fri Jun 24, 2011 10:12 am
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?
Re: Developing a PHP5 only app
Posted: Fri Jun 24, 2011 10:37 am
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:
When working with PHP5 objects, you forget about the reference sign.
Re: Developing a PHP5 only app
Posted: Mon Jun 27, 2011 10:11 am
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.
Re: Developing a PHP5 only app
Posted: Sat Jul 30, 2011 10:52 pm
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...