PostHeaderIcon Strongly Typed Collections in PHP

Updated!

The article below is about creating a strongly typed collection in PHP. It’s useful information for sure. But be sure to read the update at the end!

The Article

I’ve created a little workaround for a very common problem I experience while developing with PHP.
BTW, have to put in a little plug here for PHPStorm, now my go-to editor of choice.

The problem is best illustrated with a simple example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
class Orange {
	public $id;
	private $weight;
	public function __construct($id, $weight) {
		$this->id = $id;
		$this->weight = $weight;
	}
	public function get_weight() {
		return $this->weight;
	}
}
 
$o = new Orange(1, 4.1);
$o2 = new Orange(2, 6.4);
 
//put your oranges into an array:
$oranges = array($o, $o2);
 
//now loop through the array:
foreach($oranges as $cur_orange) {
	echo $cur_orange->get_weight(); //problem!
}
 
?>

The problem is simple. When you loop through the array, each object IS in fact an orange, but your PHP IDE doesn’t know this. It thinks all arrays contain simply Objects. As such, you won’t get any code completion when you type $cur_orange-> and your editor may even actively complain that you are trying to call an unknown method (get_weight()) on an object.

The goal is to strongly type the array so that when you’re looping through it, your editor can figure out that each item is an Orange so you can call methods on your Orange objects and most importantly, gain code completion. Well, PHP isn’t a strongly typed language like Java or C#, so we’re kind of on our own here. What can we do to help our editor to help us?

One solution to this problem is to convert each of your array objects to a bona fide Orange before calling methods on it:

1
2
3
4
5
6
<?php
foreach($oranges as $cur_orange) {
	$orange = new Orange($cur_orange->id, $cur_orange->weight);
	echo $orange->get_weight();
}
?>

But I don’t like this solution for a couple of reasons. First it’s a pain to type. Second, it’s wasteful: your $cur_orange is ALREADY an Orange! All we’re trying to do here is help our editor realize this fact.

I’ve got a better solution. A little more work upfront, but easy once you have the scaffolding up. It starts with a new PHP class I will call simply Collection:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?php
class Collection {
	private $key_prop;
	protected $array;
	/**
	 * Initialize our collection
	 * @param $key_prop The name of the property of each added 
	 * object which will identify it in this collection. If we add another
	 * object to this collection whose value for the selected property
	 * is equal to an existing one, the new object will replace the old
	 * one in our array.
	 */
	public function __construct($key_prop) {
		$this->key_prop = $key_prop;
		$this->array = array();	
	}
	/**
	 * Add an object to the internal array
	 * @param $object
	 * @return void
	 */
	public function add($object) {
		$key = $this->key_prop;
		$this->array[$object->$key] = $object;
	}
	/**
	 * Return the array of keys
	 * @return array
	 */
	public function get_keys() {
		return array_keys($this->array);
	}
	/**
	 * Retrieve an object from the array
	 * as a bona fide instance of the correct type.
	 * Subclasses should override this method and
	 * specify the class of the returned object.
	 * This enables strong typing for the collection.
	 * @param $key
	 * @return object
	 */
	public function get($key) {
		return $this->array[$key];
	}
}
?>

Armed with our base collection class, we can now make our IDE smart by subclassing it for whatever type of collection we need. In our example, we need a collection of Oranges, so we do this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
require_once('collection.php');
 
class OrangeCollection extends Collection {
	/**
	 * Override the base class method to let the IDE
	 * know that the item is an Orange
	 * @param $key
	 * @return Orange - AHA!
	 */
	public function get($key) {
		return $this->array[$key];
	}
}
?>

So our OrangeCollection class inherits its functionality from our Collection class and simply overrides the get method. And the only reason we did the override was to put the PHP-doc @return Orange in the comment so our IDE knows we’re pulling an Orange out of the collection.

Now we can do this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
$o = new Orange(1, 4.1);
$o2 = new Orange(2, 6.4);
 
/**
 * Put our oranges into the collection instead of
 * an array.  In our constructor, we tell the collection
 * that the 'id' property of each Orange is how we'll
 * identify it in the collection.
 */ 
$oranges = new OrangeCollection('id');
 
//now grab all the oranges
foreach($oranges->get_items() as $id) {
	$orange = $oranges->get($id);
	echo $orange->get_weight(); //sweet!
}
?>

Using our new OrangeCollection is easy, but just a little different than using an array. The beauty is that as soon as we type $orange->, our IDE will pop up a list of available Orange methods for us, including of course get_weight() which is the method we’re after.

To recap, if you find yourself looping through arrays of class objects and for each object, you want to set properties or call methods of that object, then your IDE needs a little help if you want to gain the power of code completion. This solution presents a simple strongly typed collection. You put objects of a certain type into your collection and when you pull them back out of the collection, your IDE knows what type of object you’re working with.

Cheers

The Update

You Probably Don’t Need A Strongly Typed Collection After All!

You learning something new every day! I found a brilliant way to solve the very problem above (helping the IDE realize that array objects are of an expected type) using only a PHP-doc comment! This is tested and works in PHP Storm and may well work in other IDEs. Witness!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php 
$o = new Orange(1, 4.1);
$o2 = new Orange(2, 6.4);
 
//put your oranges into an array:
$oranges = array($o, $o2);
 
//now loop through the array:
foreach($oranges as $cur_orange) {
	//HERE'S THE SOLUTION - create an inline type hint for your variable
	/** @var $cur_orange Orange */
	echo $cur_orange->get_weight(); //beautiful!!
}
?>

Now when you type $cur_orange->, PHPStorm will happily list all the properties and methods of your Orange class, thanks to the handy little type hint you provided. I’m both delighted and depressed. This is just the solution I was really looking for, but of course it makes the use of a strongly typed collection (like the one I showed above) completely null and void. I was prepared to pay the overhead of instantiating the additional wrapper array to hold my Collection items so that I could have the power of code completion and inspection in my IDE. The solution above gives me that power without the need for a Collection. Oh well. It was good practice!

Learn from my trials!!!

 Digg  Facebook  StumbleUpon  Technorati  Deli.cio.us 

PostHeaderIcon Viewing Android Source in Eclipse

At last, Android development has begun!

There’s a problem with setting up your Eclipse environment for Android development: the Android source code is not actually attached to the Android SDK. This makes learning and debugging Android apps more difficult because you can’t navigate the various Android classes to learn more about them from within Eclipse.

Finding a solution wasn’t particularly easy either. Here’s one that I hope works. There’s an eclipse plugin that includes the source files needed for many Android SDKs. Install the plugin as follows:

In Eclipse, go to Help > Install New Software
Click the Add button in the top right of the Window
Name: Android Sources
Location: http://adt-addons.googlecode.com/svn/trunk/source/com.android.ide.eclipse.source.update/

After installing, restart Eclipse.

CTRL + click the name of a built-in method to navigate to the declaration.
Click the change source (can’t remember the exact name of the button)
Browse to your Eclipse > plugins > com.android.ide.eclipse.source_16.0.0.201112171909
Select the correct version directory and then select sources.zip

This will do the trick.

 Digg  Facebook  StumbleUpon  Technorati  Deli.cio.us 

PostHeaderIcon PHP Type Hinting Hints

Here’s some interesting methods for implementation of some of the best parts of type checking in PHP. As you know, PHP is loosely typed, but that doesn’t mean we can’t beef it up a bit.

#1 Type hints in methods

PHP allows for type hinting in methods

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php 
class MyData {     
    public $some_var; 
    function __construct($s) {
        $this->some_var = $s;
    }
} 
//put a type hint on a method 
function do_something(MyData $data) {     
    echo $data->some_var;
}
$data = new MyData('cool!');
do_something($data); // echos 'cool!'
?>

#2 Dynamic Property Names

This doesn’t really fall under type hinting, but IMO it’s good practice. When accessing object properties when looping through arrays of objects, make the property names dynamic.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
$arr = array();
$arr[] = new MyObject('test1');
$arr[] = new MyObject('test2');
 
foreach($arr as $item) {
     // typically we just do this
    echo $item->some_var;
    /**
    * this is better practice IMO, because it reminds you
    * that you are referencing an undeclared property
    * of the array item
    */
    echo $item->{'some_var'};
}
?>

#3 Type Checking

Here’s a quick and dirty utility method for type checking an object or an array of objects.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
/**
 * Ensure the object (or the first item in the
 * array of objects) is of the specified type
 * or throw an exception
 * @static
 * @throws Exception if wrong type
 * @param $object_or_array
 * @param $class_name
 * @return bool
 */
public static function validate_instance_of($object_or_array, $class_name) {
    if(is_array($object_or_array)) {
         $to_test = $object_or_array[0];
    } else {
        $to_test = $object_or_array;
    }
    if(!is_null($to_test) && !($to_test instanceof $class_name)) {
        throw new Exception('Object or array of objects expected to be of type ' . $class_name .  ', ' . gettype($to_test) . ' received.');
    }
}
?>
 Digg  Facebook  StumbleUpon  Technorati  Deli.cio.us 

PostHeaderIcon Arrays from strings – the good way

Here’s a quality way to take a comma-delimited string and transform it into a PHP array of unique values. The sexy, one-liner version:

1
$arr = array_filter(array_unique(array_map('trim', explode(',', $str))));

The method above splits the string into an array, trims the extra spaces from each item, removes any duplicates and finally removes any empty elements. The array_filter method removes the empty strings, so that if $str is itself an empty string, the resulting array will have 0 elements as expected.

As always, it’s a good idea to transform this into a utility method. 

1
2
3
4
5
6
7
public static function from_string($s, $delimiter = ',', $remove_duplicates = false) {
    $arr = array_filter(array_map('trim', explode($delimiter, $s)));
    if($remove_duplicates) {
         $arr = array_unique($arr);
    }
    return $arr;
}
 Digg  Facebook  StumbleUpon  Technorati  Deli.cio.us 

PostHeaderIcon FDT Quirk: Linked Libraries Must Be Added From the Root Project Node

It’s a relatively minor head scratcher, but to add a linked library to a Flash project in FDT, you need to right click the root project node in the Project Explorer and click New > Linked Libraries. You do this for both individual swc’s that you want to include the source for and for entire folders.

 Digg  Facebook  StumbleUpon  Technorati  Deli.cio.us 

PostHeaderIcon Interface Driven Design

Just a quick note here. As I am developing classes, I’m trending toward using interface driven design. Interface driven design is similar to test driven design in that it forces you to consider the client user of your class as part of the core design process. As a very quick example, I’m creating a class called BuyComponent. Instead of opening up a new empty class and pondering its inner workings, I immediately write a new interface, IBuyComponent and begin filling out the methods that I think my client will need in order to use my new component. Once I’ve come up with a viable public interface for the class, I start writing the BuyComponent class and have it implement the IBuyComponentInterface. Programming in this way is really opening up doors for me. Give it a whirl yourself. The next time you need to write a component, try starting by writing an interface first, even if you can’t imagine yet how that interface will actually be used in your app.

 Digg  Facebook  StumbleUpon  Technorati  Deli.cio.us 

PostHeaderIcon GATracker TypeError: Error #1009

Using the Google Analytics component for Flash, if you receive the following error when testing your movie:
TypeError: Error #1009: Cannot access a property or method of a null object reference. at com.google.analytics.core::IdleTimer()
it’s probably because you’ve instantiated the GATracker component from ActionScript by attaching it to a MovieClip or class that hasn’t yet been added to the stage and therefore has no access to the stage.

 Digg  Facebook  StumbleUpon  Technorati  Deli.cio.us 

PostHeaderIcon Type Error 1006

Type Error 1006 – value is not a function.
2 plus hours tracking yet ANOTHER insidious bug in Flash. This one fired in an ENTER_FRAME event handler that calls the following method:

1
2
3
4
5
public function scrub_video(e:Event):void {
	var pos:Number = (m_btn_scrub.x - m_scrub_lane.x) * video_duration / m_scrub_lane.width;
	ns.seek(pos);
	m_progress.scaleX = (m_btn_scrub.x - m_scrub_lane.x) / m_scrub_lane.width;
}

This function called when I grab the scrub handle in my video player. I drag all the way to the left and BAM! Type Error 1006 with no line number reference, even from within the debugger.
Checked and rechecked a thousand times. pos never evaluates to anything less than 0. All mcs are on stage. All vars exist on every call.

The solution: Run the goddamn swf from the server instead of the IDE.

Why, Adobe? Why?

 Digg  Facebook  StumbleUpon  Technorati  Deli.cio.us 

PostHeaderIcon CS4 GUI display issues abound

Adobe has updated the GUI across the entire CS4 product line. It now uses a customized, non-standard windowing framework. <sarcasm>Thanks again Adobe. I was really frustrated with standard windows title bars, so I’m glad you overcame that problem.</sarcasm>. Of course, with Adobe’s custom UI comes new problems and bugs.

There’s a fairly serious rendering bug across all CS4 products that seems to rear its ugly head with my NVidia GeForce 8800 video card. I minimize an Adobe window and it leaves ugly fragments of the window on-screen just sitting there mixed in with the window below it. Nice.

Also, problems and display bugs ABOUND if you use Remote Desktop. I frequently sit outside and remote in to my desktop from my laptop. Whenever I open any CS4 product on my desktop PC while remoted, the Adobe GUI freaks out and basically runs havoc the windows GUI on my desktop. I’ve noticed other strange bugs while remoted in as well. One common bug is that it frequently takes Flash 30 seconds to open instead of the usual 5 seconds. Also, about 75% of the time, publishing an swf from Flash will take up to 5 whole minutes when triggered via Remote Desktop.

In short, the CS4 GUI does not play well with my NVidia card, either with or without any hardware acceleration enabled. And it also seems to react frightfully to Remote Desktop.

I so wish I could have CS1 or 2 back again.

 Digg  Facebook  StumbleUpon  Technorati  Deli.cio.us 

PostHeaderIcon Automatically add the www to incoming requests

Here’s a simple script to automatically redirect all incoming requests for http://mysite.com to http://www.mysite.com.

This script goes into an .htaccess file that sits in the root of your website (assuming Apache is your web server). If there’s no such file already in the root of your website, the quickest way to create one on Windows is to create a new text document called whatever.txt, modify and save it, and then rename the file to .htaccess (no filename, just the extension).

This script assumes Apache’s mod_rewrite module is active (enabled in http.conf or one of its included config files)

1
2
3
RewriteEngine On
RewriteCond %{HTTP_HOST} ^mysite.com
RewriteRule ^(.*)$ http://www.mysite.com/$1 [R=301]
 Digg  Facebook  StumbleUpon  Technorati  Deli.cio.us