Tag Archives: casting

A faster object in_array() for PHP 5

This is a fast and effective way of find an object in an array.

As of PHP v5.2.2 objects do not have a default response to being cast to (string). To make this tutorial work with newer PHP builds, use spl_object_hash() in place of string casting.

Introduction

When a new object is created in PHP it is assigned an internal numeric id value. The only way to destroy an object (thereby deleting its internal id) is to unset() or nullify (=NULL) all references to the object from within the script. It follows that when an object is destroyed, PHP will fill the lowest id available for the next object. For example: if objects with ids 4, 5 and 6 exist – by destroying 5, the next two objects created in PHP will have id 5 and then id 7!

These rules can be exploited to provide a much faster object in_array()!

Theory

Comparison of multidimensional objects will almost always be more processor intensive than string comparison. It occurred to me that a great deal of time could be saved by identifying objects in an array as strings. However, conventional approaches using serialize() tend to exacerbate the problem further as the function itself is quite slow. The following is the proposed function with a demo on how it could be implemented.


/***
	The proposed object_in_array function.
	***/
	function object_in_array($needle, $haystack) {
		/***
		Arguments:
			(object) $needle - The object being searched for.
			(array) $haystack - The array containing objects.
		***/
		$stringArray = array_map(create_function('$in','return (string)$in;'),$haystack);
		$objectString = (string)$needle;
		return in_array($objectString,$stringArray,TRUE);
	
	}
	
	/***
	Prepare an object needle.
	***/
	$needleObject = new stdClass;
	
	/***
	Prepare a sample array including the
	needleObject.
	***/
	$objectArray = array(
		new stdClass,
		new stdClass,
		new stdClass,
		$needleObject
	); 
	
	/***
	Uncomment the block  below to perform
	an analysis of a much larger array.
	***/
	
	/*
	for($i=0;$i < 50000;$i++) {
		$objectArray[] = new stdClass;
	}
	$objectArray[] = $needleObject;
	*/
	
	/***
	Start time-stamp
	***/
	$timeStamp = get_micro_time();
	
	/***
	NOTE: The print() function is included
	in the time analysis as it doesn't contribute
	much to the overal time required.
	***/  
	print(object_in_array($needleObject,$objectArray) ? "Found!n" : "Not found!n");
	
	/***
	End time-stamp and display.
	***/
	$timeStamp = round(get_micro_time() - $timeStamp,6);
	print("Search duration: $timeStamp ms");
	
	/***
	Auxillary timing function. Sorry,
	I can't remember where I got this function
	from or I would credit the author! Google it :-p
	***/
	function get_micro_time() {
		list($microSec, $sec) = explode(" ", microtime());
		return ((float)$microSec + (float)$sec);
	}

The above can be further optimised (clean-up the temporary array, etc.) but serves to show how the array can be copied, recast and used as a search reference for objects. Modification of the above to use the conventional in_array() or foreach() looping drastically increases the duration of the search! With very little modification to the code, the function could even return the object directly and retain the same array processing speed.

A footnote…

I had previously toyed with the idea of using a single array, casting the objects to strings and storing these as the key for each item (then using array_key_exists() ). If you’re not too worried about using the array keys / don’t use them to store useful data, this latter method can be ten-fold faster than the above example!