I call this an imaginary error, because the code that causes is never run, and it does not report an error, but the functionality breaks.

I'm developing a PHP framework. I have a debugger that writes lines to the a file throughout the execution of the framework. I noticed today that the debugger was cutting off midway through, and didn't start until the very end. (And fwrite was returning the normal int throughout) So I did my usual debugging course, and found the line of code that was causing it. It was this:

$this->error->trigger('noRoute','URL Has No Matching Route',array('URL'=>$url),'404');

The odd thing about this was that it was not being executed, yet still causing the debugger to stop. It was within an if statement that in most circumstances would not return true. I looked into the trigger() function, and found the code causing the error:

exit;

Yep, thats what was causing the problem. Although that particular line of code was not being executed, it was still halting the debugger. (die() yielded the same results) I commented that line, and other various exit; statements throughout the framework did the same thing.

This is the weirdest bug I have ever encountered. Is there a way to fix this? Is this a known bug?

Recommended Answers

All 11 Replies

$this->error->trigger('noRoute','URL Has No Matching Route',array('URL'=>$url),'404');

Isn't that code meant to be the following:

$this->$error->trigger('noRoute','URL Has No Matching Route',array('URL'=>$url),'404');

The code above will only work if $error is a method of $this and trigger() is a method of $error. Also you forgot a dollar sign for the middle variable.

Isn't that code meant to be the following:

$this->$error->trigger('noRoute','URL Has No Matching Route',array('URL'=>$url),'404');

The code above will only work if $error is a method of $this and trigger() is a method of $error. Also you forgot a dollar sign for the middle variable.

Why does he need a dollar sign? I don't think he wants it to be a dynamic call.

Also, can you post your code cloudedvision? That way we can help debug it better.

Lately I have been building my personal php framework and have a error logger like yours. It shouldn't be hard to find the problem.

Why does he need a dollar sign? I don't think he wants it to be a dynamic call.

Also, can you post your code cloudedvision? That way we can help debug it better.

Lately I have been building my personal php framework and have a error logger like yours. It shouldn't be hard to find the problem.

From what I have learnt in oop php-gtk, variables are the containers and in that code it appears to the left is the parrent - in the middle is the container and to the right is the method. If however you are trying to call two methods at the same time then that will never work and needs to be set on two lines with another container. So the previous post of mine was assuming $error was a container. If that is not the case and 'error' is a method then the following is what you may need to do:

$container=$this->error;
$container->trigger('noRoute','URL Has No Matching Route',array('URL'=>$url),'404');
//or
$container=$this->error();
$container->trigger('noRoute','URL Has No Matching Route',array('URL'=>$url),'404');

Where did it say he's using php-gtk?

He is just referencing another class through the error variable.

You also can call two methods at once with oop. All you have to do is return $this in the function.

Where did it say he's using php-gtk?

I didn't say he is using php-gtk but I said from my experience of php-gtk which is just like php.

He is just referencing another class through the error variable.

If error is a variable then the error variable will need the $ sign before it. Note that dynamic variables have $$ before the name of the variable.

You also can call two methods at once with oop. All you have to do is return $this in the function.

Although that is usually true there are some cases where that is not possible. I forget the reason but it only happens with certain objects.

-------
Also with the additional info kkeith29 has posted, perhaps the following code would be more relevant to test the problem.

$tester=$this->error;
$tester->trigger('noRoute','URL Has No Matching Route',array('URL'=>$url),'404');

If line one of the above code reports the error then you know that the error variable needs to be defined properly. If however it is the second line of the above code that reports the error then it is the trigger method that needs adjusting.

I didn't say he is using php-gtk but I said from my experience of php-gtk which is just like php.


If error is a variable then the error variable will need the $ sign before it. Note that dynamic variables have $$ before the name of the variable.


Although that is usually true there are some cases where that is not possible. I forget the reason but it only happens with certain objects.

-------
Also with the additional info kkeith29 has posted, perhaps the following code would be more relevant to test the problem.

$tester=$this->error;
$tester->trigger('noRoute','URL Has No Matching Route',array('URL'=>$url),'404');

If line one of the above code reports the error then you know that the error variable needs to be defined properly. If however it is the second line of the above code that reports the error then it is the trigger method that needs adjusting.

Dynamic variables work differently in oop. Putting a $ in front of the variable doesn't work.
ex.

$this->$error->trigger('blah');

is run as

$this->->trigger('blah');

if $error is not defined outside the class.

You do not need a $ to reference variables inside a class. I think I am misunderstanding your take on this.

Dynamic variables are irrelevant to my problem.

Here's where I set $this->error (To clear up any misunderstanding)

$this->load('classes/errorHandler');
$this->error = new errorHandler($mode, &$this->errorLog);

Heres where the problem is happening

//Now lets process the URL with routes
		$this->load('classes/route');
		$this->routeHandler = new routeHandler($this->mode, 'config/routes.php');
		if(!($this->routeVars = $this->routeHandler->checkRoutes($url))) //Usually does not return false, so the error is not triggered, but still causes problems.
			$this->error->trigger('noRoute','URL Has No Matching Route',array('URL'=>$url),'404'); //Debugger stops here
		$this->debug->log('Route processed');

Here's the error class:

class errorHandler {
	function __construct($cli, $errorLog) {
		$this->path = 'app/errors/';
		if($cli==TAM_CLI)
			$this->path .= 'cli';
		else
			$this->path .= 'web';
		$this->path .= '/';
		$this->errorLog = &$errorLog;
	}
	
	function trigger($id, $title, $details = array(), $http) {
		$this->id = $id;
		$this->details = $details;
		if($http=='404')
			header('HTTP/1.0 404 Not Found');
		require($this->path.'template.php');
		$error = 'Tamarin encountered error '.$id.'.  Associated details:';
		foreach($details as $key => $value)
			$error .= '[ '.$key.' => "'.$value.'" ]';
		$this->errorLog->log($error);
		exit; //Comment this out and the debugger works fine.... until another unexecuted exit or die() statement is stumbled upon.
	}
	
	function display() {
		require($this->path.$this->id.'.php');
	}
};

Here's the log class (Which is the class of both $this->debug and $this->errorLog)

<?php

class log {
	function __construct($args) {
		//Default values
		if(!isset($args['passive']))
			$args['passive'] = true;
		if(!isset($args['mode']))
			$args['mode'] = 'a';
		
		//Set arguments	
		$this->fn = $args['fn'];
		$this->passive = $args['passive'];
		$this->mode = $args['mode'];
		
		//If passive, don't open the file until log();
		if($this->passive)
			$this->handler = false;
		else
			$this->open();
	}
	
	//Open the file
	function open() {
		$this->handler = fopen($this->fn,$this->mode);
	}
	
	//Close the file
	function close() {
		fclose($this->handler);
		$this->handler = false;
	}
	
	//Log an entry
	function log($msg) {
		if($this->passive) //If passive, open up the file handler
			$this->open();
		
		fwrite($this->handler,time().' '.$msg.NL); //Log the error
		
		if($this->passive) //If passive, close the file handler
			$this->close();
	}
	
	function __destruct() {
		if($this->handler) //If handler is open, close it
			$this->close();
	}
};

class blankLog {
	function log($msg) {}
};

?>

If it's just dying with no message you might want to check to see if you have your error_reporting ini value set to something other than E_ALL (development only, don't turn this on live). Also, consider using braces around your conditions even if it's only one statement. It disambiguates the statements and is less confusing. I can't tell you how many times I've forgot the braces then added another statement and wondered why it didn't execute.

Also, your classes are dynamically instantiating members you should probably define them before-hand to make things easier, ie.,

class Log
{
  /**
  * File handle for the log
  * @var Resource
  */
  private $handler = NULL;

Its definitely E_ALL, my framework automatically sets it to that in development mode. fwrite returns an integer, not false, so there is no error there. (But for some reason it doesn't work)

I've heard the tip about using brackets always, but I've never have bothered because I don't forget to add brackets when I add another statement. (Which is weird, I always end up forgetting to close up multiple parenthesis, add periods to connect strings and variables, etc.)

Its definitely E_ALL, my framework automatically sets it to that in development mode. fwrite returns an integer, not false, so there is no error there. (But for some reason it doesn't work)

I've heard the tip about using brackets always, but I've never have bothered because I don't forget to add brackets when I add another statement. (Which is weird, I always end up forgetting to close up multiple parenthesis, add periods to connect strings and variables, etc.)

Well its more of a style choice really but if you're building a framework it usually means you're going to release it to the public and I'd say a majority of programmers whether they use Allman/BSD or K&R/OTBS style they do prefer to have closing braces.

In your trigger function always exit after a header() call so in that case you will need the braces because of having 2 statements. You don't need the other exit so just move it right after the header() call inside that condition

$this->load('classes/errorHandler');$this->error = new errorHandler($mode, &$this->errorLog);

That makes more sense because I was thinking along the lines of $error = new errorHandler($mode, &$this->errorLog); . Although I'm not a big fan of pure oop pages I would suggest to check if trigger is a member/method of the error object.
Although I would have to say I haven't seen somebody define an object using that style before but there isn't much more that I can recommend.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.