webdevRefinery Forum: Autoloading your Classes using Namespaces - webdevRefinery Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

User is offline AwesomezGuy 

  • Certified Asshole™
  • Group: Members
  • Posts: 1245
  • Joined: 08-March 10
  • LocationIreland
  • Expertise:HTML,CSS,PHP,Javascript,SQL

Posted 30 January 2011 - 11:06 AM (#1)

Autoloading your Classes using Namespaces


PHP 5.3+ users only!
Autoloading your Classes using Namespaces
Written by AwesomezGuy, 30th January 2011


Introduction
Sup guys? I decided I'd write a nice tutorial into autoloading your classes into your project, and also to structure your files in a nice user friendly way (I got the approach I'll be using in this tutorial from Kyek, so thank you to him :)).

Step 1, Your File Structure
In order to do this we're going to need to get your classes nice and organized, let's go through a few rules we'll be following
  • 1 Class per File - NO dissident says it is unprofessional to swear in a tutorial, so I removed this naughty word EXCEPTIONS
  • Classes should be organized into groups, we don't want to lob them in all together

Let's get going with the structure!

Start by creating a folder called "lib" in your project's base directory. lib stands for library, so in future if you ever plan to use REcaptcha or something, you'll have a great place to drop that, and if you're using hydrogen it'll definitely need to go in here.

Now, the next thing you need to get into your head, we're going to think of your project's classes as a library. For this example, I'll just pretend the project in question is called myproject.
So inside that lib folder, you'll want to create a myproject folder.
So now we have /lib/myproject.

Next up! We need to start grouping your classes together! Let's say you have a few classes centred around your user system.
Let's think of them as classes called User, UserPermissionSet and UserGroup.
So we now create a folder called user inside myproject.
We now have /lib/myproject/user.
Now inside user we're going to create 3 files, User.php, UserPermissionSet.php and UserGroup.php, inside those files, we put classes named the same as the filename (minus the .php).
Woot! We now have the following:
  • /lib/myproject/user/User.php
  • /lib/myproject/user/UserPermissionSet.php
  • /lib/myproject/user/UserGroup.php

Group all your classes like that and repeat the process, in the end you'll have a bunch of folders with class files inside them. :)

Step 2, Add namespaces to the files
So we have our lovely structure. Now you might be wondering why we structured everything like that. Sure, it's nice to be neat and tidy, but was that really necessary?
Yes, it was, is my answer.
When we get to the autoloading, the files are going to need to be in a structure which in someway resembles the namespaces.
Let's take our UserGroup class for example.
It's in /lib/myproject/user/UserGroup.php
The full namespace that will be used is going to be myproject\user\UserGroup, understand now? :)

So now we have to add the namespace line to the top of all your class files.
At the top of /lib/myproject/user/UserGroup.php, we'd put
namespace myproject\user;
The last part is filled in with the class name, so we don't need to put that there.
Repeat that process for every class file you have, substituting user for the group of classes you're operating in.

Step 3, Add the autoloader
Now for the autoloader, here's an autoloader we'd use for myproject. We put it in /lib/myproject/myproject.inc.php:

<?php
namespace myproject;

function load($namespace) {
	$splitpath = explode('\\', $namespace);
	$path = '';
	$name = '';
	$firstword = true;
	for ($i = 0; $i < count($splitpath); $i++) {
		if ($splitpath[$i] && !$firstword) {
			if ($i == count($splitpath) - 1)
				$name = $splitpath[$i];
			else
				$path .= DIRECTORY_SEPARATOR . $splitpath[$i];
		}
		if ($splitpath[$i] && $firstword) {
			if ($splitpath[$i] != __NAMESPACE__)
				break;
			$firstword = false;
		}
	}
	if (!$firstword) {
		$fullpath = __DIR__ . $path . DIRECTORY_SEPARATOR . $name . '.php';
		return include_once($fullpath);
	}
	return false;
}

function loadPath($absPath) {
	return include_once($absPath);
}

spl_autoload_register(__NAMESPACE__ . '\load');

?>


Substitute the namespace for the name of your project and save the file.

Step 4, Include the autoloader into your project and use the classes :)
Final step. You need to add the following line to any file which uses your classes, if you're using an MVC pattern, this will only be one file.
require_once("lib/myproject/myproject.inc.php");

Obviously, substitute instances of myproject with your project's name.

Now, just use the following line to use your classes (pun intended) ;)
use myproject\user\UserGroup;

By now I seriously hope you know what you need to substitute in that line, if you don't, go read this entire thing again- slowly. :P

Hope you enjoyed that tutorial, if you have any questions feel free to ask below!
5


User is offline Sync 

  • Group: Members
  • Posts: 336
  • Joined: 20-April 10
  • LocationLondon
  • Expertise:HTML,CSS,PHP

Posted 30 January 2011 - 11:24 AM (#2)

Nice tutorial, very useful!
deviantART users, join the webdevRefinery group!

My personal blog and gallery, imvin.co.uk
watch me on deviantART
follow me on twitter
0


User is offline callumacrae 

  • {{ post.author }}
  • Group: Members
  • Posts: 2862
  • Joined: 20-January 11
  • LocationWarwickshire, England
  • Expertise:HTML,CSS,PHP,Javascript,Node.js,SQL

Posted 30 January 2011 - 11:25 AM (#3)

Nice, now I just have to persuade my VPS to accept 5.3! :D

~Callum
Front-end developer and writer
Twitter | GitHub | phpBB Contributor and Website Team Member | lynxphp
0


User is offline ShanePerreault 

  • Sleep Burns My Eyes
  • Group: Members
  • Posts: 1075
  • Joined: 19-March 10
  • LocationChicago, USA
  • Expertise:PHP,Java,Javascript,Ruby on Rails,SQL

Posted 30 January 2011 - 12:10 PM (#4)

This answers my question greatly, thanks man.

Languages: PHP | JS | Ruby | Rails | C# | Python | Java
0


User is offline Leamsi 

  • RoyLee KinsJen
  • Group: Members
  • Posts: 806
  • Joined: 18-March 10
  • LocationJonas Brothers Concerts

Posted 30 January 2011 - 03:26 PM (#5)

Great tu, might use it sometime :D
"Years ago I got addicted to this one drug, it made me feel happy and awesome. It was music." -Koen
Posted Image
(I admin this server, drop by, and ask for Ismael!)
0


User is offline Kyek 

  • Founder of wdR
  • Group: Administrators
  • Posts: 5078
  • Joined: 20-February 10
  • LocationPhiladelphia, PA, USA
  • Expertise:HTML,CSS,PHP,Java,Javascript,Node.js,SQL

Posted 30 January 2011 - 04:57 PM (#6)

Nice ;-). Although, you should revisit that autoloader code! I have no idea what the hell I was thinking when I wrote it, because I'm exploding the namespace in order to change the backslash character to a forward slash ... when I could have done a MUCH more efficient str_replace to get the same effect. If you look at the new hydrogen.inc.php, that's the method I use (example from the MVC starter). I also have some fancy footwork in there to make sure the "Class Not Found" error will happen in the file that's 'use'ing a class that doesn't exist, rather than in the autoloader file. That old autoloader adds an embarrassing bit of overhead every time a class is used. (Oh, and the loadPath() function is never called, there -- that's only in the hydrogen autoloader so that other classes can call it)

The giant (giant) benefit of how I do it vs. how most other frameworks do it is that there's no checking to see if a file exists in my code. Doing that check causes multiple stat() calls, which cause hard disk interaction, which is the absolute biggest slowdown for a webapp. So I avoid checks altogether. Preparing for an error wastes time before every include -- not preparing for it but catching the error when it happens only takes time if a file isn't found, which will never happen in production. That's the whole theory Hydrogen is based on ;-).

Not to be a douche, though, but in order to maintain my copyright on Hydrogen, I have to insist that you follow the license if you distribute that code :-/. The copyright notice has to be at the top, or I lose copyright holder control. Sorry man :-/.
0


User is offline Daniel15 

  • dan.cx
  • Group: Moderators
  • Posts: 3415
  • Joined: 17-April 10
  • LocationMelbourne, Australia
  • Expertise:HTML,CSS,PHP,Java,Javascript,Node.js,SQL

Posted 30 January 2011 - 05:00 PM (#7)

Looks good. you should add more comments to the autoloader function so we know what it's doing :P

For what it's worth, this is the autoloader I "made" ("made" because most of the actual work is done by the default PHP autoloader :P). Doesn't support namespaces though. Lowercases the class name, splits it up by underscore and looks for it (eg. Test_Class_Blah would correspond to test/class/blah.php):
define('BASEDIR', __DIR__);
set_include_path(get_include_path() . PATH_SEPARATOR . BASEDIR);

/**
 * Load the class specified 
 * @param	string		Class to load
 */
function autoload($className)
{
	/* We're using the built-in autoloader as it's faster than a PHP implementation.
	 * Replace underscores with slashes to use a directory structure (FeedSources_Twitter -> includes/FeedSources/Twitter.php)
	 */
	$filename = strtolower(str_replace('_', '/', $className));
	return spl_autoload($filename);
}

spl_autoload_register('autoload');


Quote

You need to add the following line to any file which uses your classes, if you're using an MVC pattern, this will only be one file.

Not just MVC pattern, but any design pattern. Once you add the autoloader, it should work with anything. I've used autoloaders for tiny projects before, it just makes it easier :D

Quote

now I just have to persuade my VPS to accept 5.3!

If it's a VPS you should be able to upgrade it yourself :)
Daniel15! :D
Posted Image

Repeat after me: jQuery is not JavaScript. It is not the answer to every JavaScript-related question. When you have to write some JavaScript, do not instantly react with "Oh, I'll do that with jQuery!"

Spoiler
0


User is offline AwesomezGuy 

  • Certified Asshole™
  • Group: Members
  • Posts: 1245
  • Joined: 08-March 10
  • LocationIreland
  • Expertise:HTML,CSS,PHP,Javascript,SQL

Posted 30 January 2011 - 05:46 PM (#8)

View PostKyek, on 30 January 2011 - 04:57 PM, said:

Nice ;-). Although, you should revisit that autoloader code! I have no idea what the hell I was thinking when I wrote it, because I'm exploding the namespace in order to change the backslash character to a forward slash ... when I could have done a MUCH more efficient str_replace to get the same effect. If you look at the new hydrogen.inc.php, that's the method I use (example from the MVC starter). I also have some fancy footwork in there to make sure the "Class Not Found" error will happen in the file that's 'use'ing a class that doesn't exist, rather than in the autoloader file. That old autoloader adds an embarrassing bit of overhead every time a class is used. (Oh, and the loadPath() function is never called, there -- that's only in the hydrogen autoloader so that other classes can call it)

The giant (giant) benefit of how I do it vs. how most other frameworks do it is that there's no checking to see if a file exists in my code. Doing that check causes multiple stat() calls, which cause hard disk interaction, which is the absolute biggest slowdown for a webapp. So I avoid checks altogether. Preparing for an error wastes time before every include -- not preparing for it but catching the error when it happens only takes time if a file isn't found, which will never happen in production. That's the whole theory Hydrogen is based on ;-).

Not to be a douche, though, but in order to maintain my copyright on Hydrogen, I have to insist that you follow the license if you distribute that code :-/. The copyright notice has to be at the top, or I lose copyright holder control. Sorry man :-/.


Yeah I did revisit the file, but I noticed a whole load of extra things with HYDROGEN written in them, and I decided to not bother putting it here until I'd tested using it myself, otherwise the tutorial would be useless.
I'll go get your license thingy and readd it once I'm on my computer, I didn't actually remove it, just I only copy pasted the class into my own include file, and from that is where I got the code for the guide. So there's no problem readding it. :)
0


Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users


Enter your sign in name and password


Sign in options
  Or sign in with these services