2010


31
Dec 10

Let’s Try This…

I’ve decided I want to blog more. Rather than just thinking about doing it, I’m starting right now (er…well… in 1 day…). I will be posting on this blog once a week for all of 2011.

I know it won’t be easy, but it might be fun, inspiring, awesome and wonderful. Therefore I’m promising to make use of The DailyPost, and the community of other bloggers with similiar goals, to help me along the way, including asking for help when I need it and encouraging others when I can.

If you already read my blog, I hope you’ll encourage me with comments and likes, and good will along the way.

Signed,

SeanJA


27
May 10

Orms and Circular References

In my spare time I have been working on an ORM… not one meant to be used in the real world (well… not yet anyway). I currently have hasOne and hasMany working like so:

<?php
 
/**
 * @property int $id
 * @property string $type
 * @property int $car_id
 */
class wheelBoilerplate extends orm{
	protected function init(){
		$this->addProperty('type', array(
			'type'=>'string',
			'default'=>'monster truck',
		));
		$this->hasOne('car');
	}
}
 
class wheel extends wheelBoilerplate{}
 
/**
 * @property int $id
 * @property int $wheel_count
 * @property array $wheels
 * @property string $type
 */
abstract class carBoilerplate extends orm{
	protected function init(){
		$this->addProperty('wheel_count', array(
			'default'=>4,
			'type'=>'int',
		));
		$this->addProperty('type', array(
			'default'=>'monster truck',
			'type'=>'string',
		));
		$this->hasMany('wheels');
	}
}
 
class car extends carBoilerplate{}
 
$car = new car();
 
echo $car->wheels[0]->car->wheels[2]->car->wheels[3]->car->wheels[0]->type; #=> 'monster truck'

The problem as you can probably guess, is you now have 4 of the same car loaded into memory, and 4 wheels, 2 of which are the same. So, when you do this:

$car->type = 'Ford Pinto';

You are only actually changing one instance of all of the instances of car that you have created in memory. Not so good for keeping things straight, which one do you save? What happens if you save one over top of the other?

$car->type = 'Ford Pinto';
$car->save();
$car->wheels[0]->car->save();

You have just overwritten your changes in the database. I didn’t think that was a good thing to let someone do (even accidentally). That is where this class came from:

<?php
 
class factory {
	/**
	 * Holds all of the items in the factory
	 * @var array
	 */
	protected static $created = array();
	/**
	 * Create/Load an object from the factory
	 * @param string $className
	 * @param int $id
	 * @return orm
	 */
	public static function Create($className, $id=null ) {
		$className = strtolower($className);
		if(!isset(self::$created[$className][$id])) {
			self::$created[$className][$id] = new $className($id);
		}
		return self::$created[$className][$id];
	}
	/**
	 * Load an object from the factory
	 * @param string $className the object's class
	 * @param int $id the id of the object you are loading
	 * @return orm or null
	 */
	public static function Load($className, $id ) {
		$className = strtolower($className);
		return (isset(self::$created[$className][$id]))? self::$created[$className][$id]:null;
	}
	/**
	 * Add an object to the factory, has no effect if the object is already part of the factory
	 * @param string $className
	 * @param orm $class
	 */
	public static function Add(orm &$class) {
		$className = strtolower($class->class_name);
		if(!isset(self::$created[$className][$class->id])) {
			self::$created[$className][$class->id] = &$class;
		}
	}
	/**
	 * Destroy an instance of something in the factory and the object itself
	 * @param orm $class the class being destroyed
	 */
	public static function Destroy(orm &$class){
		$className = strtolower($class->class_name);
		$id = $class->id;
		unset(self::$created[$className][$id]);
		$class = null;
	}
}

I haven’t had the chance to actually merge them together, but this is how it should work:

 
$car = factory::Create('car', 1);
 
$car->wheels[0]; //#=> factory::Create('wheel', 1);
$car->wheels[1]; //#=> factory::Create('wheel', 2);
$car->wheels[2]; //#=> factory::Create('wheel', 3);
$car->wheels[3]; //#=> factory::Create('wheel', 4);
 
$car->wheels[0]->car; //#=> factory::Load('car', 1);
$car->wheels[0]->car->wheels[0]; //#=> factory::Load('wheel', 1);
 
$car->wheels[0]->car->type = 'Ford Pinto';
 
echo $car->type; //#=> 'Ford Pinto'

Now, no matter which of the cars that you load (as long as it has the same ID), it will be the same one instead of just another instance of the same one. Changes are made to all of them, because they are all the same instance of that car.

The factory class and some sample usage code are on github, if’n you want to look at it, or fork it, or whatever.


29
Apr 10

Netbeans 6.9: My New Favourite Features

Netbeans 6.9 beta was recently released, here are some of the new features for the PHP editor that are pretty awesome.

The first one is recognizing overridden methods and classes. This feature is great because it allows for better auto completion, and lets you find things faster.

Not only does it recognize that I am extending the class, it recognizes that the function I am writing is overriding a function in the parent class, and provides hints as to what that function did (based on the comments that you *did* write right?).

After you hit enter (because you actually want to override that function, you get this (including a call to parent::functionName()):

There is a little green circular O icon beside your function because it is overriding a parent function (granted this would make more sense if I were using __construct rather than php4 syntax). Hovering over the O tells you which function you are overriding, and where it is. Clicking on that icon will take you to the actual declaration of that function:

You will notice that there is a different green O icon (a square one this time, with a small black arrow. Hovering over that will tell you that the function/class “Is Overridden”. Clicking on it will give you the locations that Netbeans found it to be overridden. Clicking on one of those will take you to the location that it is being overridden.

The second feature that is quite neat is the updated commit dialog.

The first thing you will notice (if you used previous versions of Netbeans) is that they added checkboxes beside the files, much more intuitive than the way it was before (a bunch of drop downs that you would miss if you didn’t know they were there).

You can also now right-click on the files you are committing and there is now an option to view the diff of the file you have selected. Selecting the Diff option will show you the familiar diff view:

The second tab (Textual) will let you create a patch file from your changes:

This new tab also shows up in the Diff view, and you can create patches from the diff between two files (not sure how useful that actually is when they are completely different files), or the changes you have made to a single file.

In addition to the old badges for modified files (blue icon on parent folders, blue text) and new files (blue icon on parent folders, green text), there is now an error badge (red icon on the file) which will show up when there are errors in a file.

There are lots of other new features including ini syntax colouring, more formatting options, go to css declaration, it will display the value of a constant you are using.

There are of course many other new features unrelated to what I do every day, you should go check it out for yourself.


21
Apr 10

Exceptions Are Not For Flow Control

When I saw this post on Better Error Handling, while there is nothing horribly horribly wrong with it I couldn’t help thinking that he has gone past proper error handling. Exceptions are for exceptional cases, hence the name. They should not to be used for flow control, or for things that could occur normally like a user failing to login.

This is because almost all function calls are basically a question:

  • Did the user enter the correct information to login? Yes, No
  • Did the database query return data? Here is the data array, here is an empty array.
  • Is the data that the user entered valid? Yes, No.

Within these functions, you can pass an error to the next screen, view, wherever you are returning to because the function failed to produce a positive result.

Things that are exceptional cases would be something similar to the following. In these cases, you cannot continue because the assumptions made by your code were not fulfilled.

  • A malformed query on the database (MalformedDatabaseQueryException)
  • no connection to the database (DatabaseMissingException)
  • the database timed out (DatabaseWentAwayException)
  • A file is deleted while you are reading/writing it (FileWentAwayException)
  • trying to call a function that takes an integer by passing it a string, object or array (InvalidDataTypeException)

The problem with using exceptions for flow control is that you will inevitably end up with something like this if you want to handle each exception individually:

<?php
try{
	$user->login();
} catch(InvalidDataException $e){
	//handle invalid data exception
}catch(CouldNotLogInException $e){
	//handle could not login
}catch(DatabaseException $e){
	//handle database exception
}

Or something like this if you don’t want to check all possible errors:

 
<?php
try{
	$user->login();
} catch(Exception $e){
	//handle exception
}

The problem with the second one is that now you are treating all exceptions the same way regardless of their actual severity.

Or, if you are validating data:

try{
	validateUsername($_POST['username']);
} catch(Exception $e){
	//handle exception
}
 
try{
	validatePassword($_POST['password']);
} catch(Exception $e){
	//handle exception
}
 
try{
	validateDateOfBirth($_POST['birthday']);
} catch(Exception $e){
	//handle exception
}
 
try{
	validateTwitterAccount($_POST['twitter_account']);
} catch(Exception $e){
	//handle exception
}
//and so on...

Or if you are lazy:

try{
	validateUsername($_POST['username']);
	validatePassword($_POST['password']);
	validateDateOfBirth($_POST['birthday']);
	validateTwitterAccount($_POST['twitter_account']);
} catch(Exception $e){
	//handle exception
}

But then you can only show the user the first thing that failed. Which is not good from a usability perspective because they might have messed up everything after the username, and would then have to submit the form 4 times.

Instead you could do this:

/**
 * Show the fatal error page when an exception occurs
 * @var Exception $exception;
 */
function myExceptionHandler($exception){
	displayErrorPage($exception->getMessage());
}
set_exception_handler('myExceptionHandler');
 
$u = new user();
$u->username = $_POST['username'];
$u->password = $_POST['password'];
$u->birthday = $_POST['birthday'];
$u->twitter_account = $_POST['twitter_account'];
if($u->save()){
	//continue to the next page with a confirmation message
} else {
	//show the user the errors that occurred on the page they just came from
}

Which is a much nicer alternative.


14
Apr 10

PHP Functions, you’re doing it wrong…

Just a quick tip today. If your function looks something like this:

 
<?php
/**
 * A really long function definition
 * @param string $has
 * @param bool $a
 * @param int $lot
 * @param float $of
 * @param assoc_array $parameters
 * @param string $I
 * @param string $wonder
 * @param int $what
 * @param int $they
 * @param int $do 
 */
function myfunction(
	$has=null,
	$a=null,
	$lot=null,
	$of=null,
	$parameters=null,
	$I=null,
	$wonder=null,
	$what=null, 
	$they=null,
	$do=null
	){
	//do some magic
}
 
//this is how it would be called
myfunction(null, false, null, 1.2, array('one'=>1, 'two'=>2), 'I', null, 1, null, 3);

You are doing it wrong, if all of these parameters are really nullable and required for your function, and there is no way for you to split it up, then you _can_ refactor it like this:

 
<?php
/**
 * Quickly refactored to make it easier to use
 * @param array $array containing: (string)'has', (bool)'a', (int)'lot', (float)'of', (assoc_array)'parameters', (string)'I', (string)'wonder', (int)'what', (int)'they', (int)'do'
 */
function myFunction(array $array){
	//make sure we are only taking in parameters that we recognize...
	$has = isset($array['has'])? $array['has']:null;
	//array key exists because it is a fake boolean value... it has 3 possibilities
	$a = array_key_exists('a', $array)? $array['a']:null;
	$lot = isset($array['lot'])? $array['lot']:null;
	$of = isset($array['of'])? $array['of']:null;
	$parameters = isset($array['parameters'])? $array['parameters']:null;
	$I = isset($array['I'])? $array['I']:null;
	$wonder = isset($array['wonder'])? $array['hwonders']:null;
	$what = isset($array['what'])? $array['what']:null;
	$they = isset($array['they'])? $array['they']:null;
	$do = isset($array['do'])? $array['do']:null;
 
	//some magic
}
 
//it could also be written:
 
/**
 * Quickly refactored to make it easier to use
 * @param array $array containing: (string)'has', (bool)'a', (int)'lot', (float)'of', (assoc_array)'parameters', (string)'I', (string)'wonder', (int)'what', (int)'they', (int)'do'
 */
function myFunction(array $array){
	//make sure we are only taking in parameters that we recognize...
	$args = array('has', 'a', 'lot', 'of', 'parameters', 'I', 'wonder', 'what', 'they', 'do');
	foreach($args as $arg){
		$$arg = array_key_exists($arg, $array)? $array[$arg]:null;
	}
	//some magic
}
 
 
 
//this is how it would be called
//equivalent to:
//myfunction(null, false, null, 1.2, array('one'=>1, 'two'=>2), 'I', null, 1, null, 3);
myfunction(array('a'=> false, 'lot'=>1.2, 'parameters'=>array('one'=>1, 'two'=>2), 'I'=>'I', 'what'=>1, 'do'=>3));

It may be more to type, but it is harder to get it wrong when you are using named parameters. You don’t have to remember what each of the parameters do in their specific positions either so it is easier to understand the code as you quickly glance at it. Note that this is similar to the way that a lot of ruby functions are written, except we don’t have a short hand for named parameters like they do (it would be awesome if we did…):

 
myfunction(:a => false, :lot => 1.2, :parameters => { :one => 1, :two => 2 }, :I => 'I', :what => 1, :do => 3)

While this is definitely easier to read and remember, it is probably worth refactoring a function like this (as it is an extreme case) further because it is likely that you are doing way too many things within it.