PHP 5 exceptions to PHP 4

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
fastfingertips
Forum Contributor
Posts: 242
Joined: Sun Dec 28, 2003 1:40 am
Contact:

PHP 5 exceptions to PHP 4

Post by fastfingertips »

Hello guys

I’m in middle of a task that involves rewriting some PHP 5 classes to PHP 4 and I have somehow to simulate the PHP 5 exception system (since any error must be handled at a superior level). Any idea how I will be able to do that? I was thinking to create an observer and make all objects that are triggering error observable, but this will involve some hard work so this is my last solution.
User avatar
Weirdan
Moderator
Posts: 5978
Joined: Mon Nov 03, 2003 6:13 pm
Location: Odessa, Ukraine

Post by Weirdan »

other approach would be to use set_error_handler() & trigger_error()
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

I've got this (it's not the best, I know):

Code: Select all

<?php

class MyException extends Swift_Exception {}

class TestOfErrors extends UnitTestCase
{
	function setUp()
	{
		Swift_Errors::reset();
	}
	
	function testErrorIsTriggeredIfItNotCaught()
	{
		$ex =& new Swift_Exception("Foo");
		Swift_Errors::trigger($ex);
		$this->assertError(); //SimpleTest's of course
		
		$ex =& new Swift_Exception("BAR");
		Swift_Errors::trigger($ex);
		$this->assertError(); //SimpleTest's of course
	}
	
	function testErrorCanBeCaught()
	{
		$ex =& new Swift_Exception("foo");
		Swift_Errors::expect($e);
		Swift_Errors::trigger($ex);
		$this->assertEqual($e, $ex);
		
		$ex =& new Swift_Exception("bar");
		Swift_Errors::expect($e);
		Swift_Errors::trigger($ex);
		$this->assertEqual($e, $ex);
	}
	
	function testOnlyOneErrorCaught()
	{
		$ex =& new Swift_Exception("foo");
		Swift_Errors::expect($e);
		Swift_Errors::trigger($ex);
		$this->assertEqual($e, $ex);
		
		
		$ex =& new Swift_Exception("bar");
		Swift_Errors::trigger($ex);
		$this->assertError();
	}
	
	function testErrorTypeCanBeSpecified()
	{
		$ex =& new MyException("test");
		Swift_Errors::trigger($ex);
		$this->assertError();
		
		$ex =& new MyException("test2");
		Swift_Errors::expect($e, "MyException");
		Swift_Errors::trigger($ex);
		$this->assertEqual($e, $ex);
	}
	
	function testErrorTypeKnowsAboutInheritance()
	{
		$ex =& new MyException("test2");
		Swift_Errors::expect($e, "MyException");
		Swift_Errors::trigger($ex);
		$this->assertEqual($e, $ex);
		
		$ex =& new MyException("test2");
		Swift_Errors::expect($e, "Swift_Exception");
		Swift_Errors::trigger($ex);
		$this->assertEqual($e, $ex);
	}
	
	function testCatchStatementsCanBeEndedWithoutThrowingException()
	{
		$ex =& new MyException("test2");
		Swift_Errors::expect($e, "MyException");
		//Swift_Errors::trigger($ex); let's not throw this one!
		Swift_Errors::clear("MyException");
		$ex =& new MyException("test3");
		Swift_Errors::trigger($ex);
		$this->assertError();
	}
	
	function testCatchStatementsCanBeNested()
	{
		$ex1 =& new MyException("ex1");
		$ex2 =& new MyException("ex2");
		Swift_Errors::expect($e1, "MyException");
		Swift_Errors::expect($e2, "MyException");
		Swift_Errors::trigger($ex1);
		Swift_Errors::trigger($ex2);
		$this->assertEqual($e1, $ex2);
		$this->assertEqual($e2, $ex1);
	}
	
	function testRealCaseScenario()
	{
		Swift_Errors::expect($e, "MyException");
		if (true) {
			Swift_Errors::trigger(new MyException("foo"));
		} else {
			Swift_Errors::clear("MyException");
		}
		$this->assertIsA($e, "MyException");
		$this->assertEqual("foo", $e->getMessage());
		
		Swift_Errors::expect($e, "MyException");
		if (false) {
			Swift_Errors::trigger(new MyException("foo"));
		} else {
			Swift_Errors::clear("MyException");
		}
		$this->assertNull($e);
		
		if (true) {
			Swift_Errors::trigger(new Swift_Exception("bar"));
		} else {
			Swift_Errors::clear("MyException");
		}
		$this->assertError();
	}
}

Code: Select all

<?php

/**
 * Swift Mailer PHP4 Exception hackaround.
 * Please read the LICENSE file
 * @author Chris Corbyn <chris@w3style.co.uk>
 * @package Swift
 * @license GNU Lesser General Public License
 */


/**
 * Swift Exception handling object for PHP4
 * Triggers and/or catches errors
 * @package Swift
 * @author Chris Corbyn <chris@w3style.co.uk>
 */
class Swift_Errors
{
	/**
	 * Caught errors
	 * @var array,Swift_Error
	 */
	var $errors = array();
	/**
	 * If an error has been thrown previously and not caught (hack)
	 * @var boolean
	 */
	var $halt = false;
	/**
	 * Errors we're expecting, so don't trigger them
	 * @var array
	 */
	var $try = array();
	
	/**
	 * Get an instance of this class as a singleton - needed internally
	 * @return Swift_Errors
	 */
	function &getInstance()
	{
		static $instance = null;
		if (!$instance) $instance = array(new Swift_Errors());
		return $instance[0];
	}
	/**
	 * Check if things are supposed to have stopped processing because of an
	 * uncaught excpetion
	 * @return boolean
	 */
	function halted()
	{
		$me =& Swift_Errors::getInstance();
		return $me->halt;
	}
	/**
	 * Reset everything logged so far
	 */
	function reset()
	{
		$me =& Swift_Errors::getInstance();
		$me->errors = array();
		$me->halt = false;
		$me->try = array();
	}
	/**
	 * Throw a new exception - it will either be caught or triggered
	 * @param Swift_Exception
	 */
	function trigger(&$e)
	{
		$me =& Swift_Errors::getInstance();
		$me->errors[] =& $e;
		$me->halt = true;
		foreach (array_reverse(array_keys($me->try)) as $type)
		{
			if (is_a($e, $type))
			{
				foreach (array_reverse(array_keys($me->try[$type])) as $i)
				{
					$me->try[$type][$i] = $e;
					unset($me->try[$type][$i]);
					$me->halt = false;
					return;
				}
			}
		}
		//If here, then it wasn't caught
		$me->dumpError($e);
	}
	/**
	 * Dump the error if it was not caught
	 * @param Swift_Exception
	 */
	function dumpError(&$e)
	{
		$output = "<br /><strong>Uncaught Error</strong> of type [" . get_class($e) . "] with message [" . $e->getMessage() . "]";
		$output .= "<br />" . $e->getBacktraceDump() . "<br />";
		trigger_error($output, E_USER_ERROR);
	}
	/**
	 * Tell the error handler we're expecting an error of type $type and assign it to $e
	 * @param &$e
	 * @param string The type of expection - optional
	 */
	function expect(&$e, $type="Swift_Exception")
	{
		$me =& Swift_Errors::getInstance();
		$e = null;
		$me->try[$type][] =& $e;
	}
	/**
	 * Clear anything that may have been expected matching $type
	 * @param string The type
	 */
	function clear($type)
	{
		$me =& Swift_Errors::getInstance();
		if (isset($me->try[$type]))
		{
			foreach (array_reverse(array_keys($me->try[$type])) as $i)
			{
				unset($me->try[$type][$i]);
				break;
			}
		}
	}
	/**
	 * The last error message as a string
	 * @return string
	 */
	function getLast()
	{
		$me =& Swift_Errors::getInstance();
		if (count($me->errors))
		{
			$last =& $me->errors[(count($me->errors)-1)];
			return $last->getMessage();
		}
	}
	/**
	 * Get all logged errors as an array
	 * @return array,Swift_Exception
	 */
	function &getAll()
	{
		return $this->errors;
	}
}

Code: Select all

<?php

/**
 * Swift Mailer PHP4 Exception.
 * Please read the LICENSE file
 * @author Chris Corbyn <chris@w3style.co.uk>
 * @package Swift
 * @license GNU Lesser General Public License
 */


/**
 * Swift Exception for PHP4.
 * @package Swift
 * @author Chris Corbyn <chris@w3style.co.uk>
 */
class Swift_Exception
{
	/**
	 * The error message in this exception
	 * @var string
	 */
	var $message;
	/**
	 * A backtrace to show
	 * @var array
	 */
	var $trace;
	
	/**
	 * Constructor
	 * @param string The error message
	 */
	function Swift_Exception($message)
	{
		$this->message = $message;
		$this->trace = debug_backtrace();
	}
	/**
	 * Get the error message
	 * @return string
	 */
	function getMessage()
	{
		return $this->message;
	}
	/**
	 * Get the backtrace
	 * @return array
	 */
	function getTrace()
	{
		return $this->trace;
	}
	/**
	 * Get a summarised backtrace as a string
	 * @return string
	 */
	function getBacktraceDump()
	{
		$trace = $this->getTrace();
		$ret = "";
		for ($i = 0; $i < count($trace); $i++)
		{
			$end = array_pop($trace);
			if (!empty($end["class"])) $class = $end["class"] . "::";
			else $class = "";
			
			$file_info = " @$i " . $class . $end["function"] .
			"() in " . $end["file"] . " on line " .
			$end["line"] . "<br />";
			
			$ret .= $file_info;
		}
		return $ret;
	}
}
Post Reply