I am trying to implement a catch-all exception handler in PHP such that it will set the status code of the response to the status contained in the exception (if present), but for some reason when I pass what is definitely an integer (because I am logging gettype()) into a function, it is somehow turning into a string on the way to that function because if I log its type immediately in the function it is now a string!
Clearly I don't know enough about PHP because this is confounding the heck out of me. Why on earth would this ever happen and how do I stop it from happening?
function qpGlobalExceptionHandler($e) {
$code = intval($e->getCode());
error_log("Global exception (".$code." ".gettype($code)."): ".$e->getMessage());
$this->sendReply($code, $e->getMessage(), false);
}
At this point in the error log I see:
Global exception (404 integer): CouchDB Error: not_found (deleted) …
But inside sendReply, which looks like this:
public function sendReply($responseCode,$responseText=false,$allowCaching=true) {
error_log("In sendReply. gettype(responseCode): ".gettype($responseCode));
// ...
}
In the error log I get:
In sendReply. gettype(responseCode): string
Now I know PHP can be weird, but what the heck?
Update: So I realized one problem, and that was that I was referencing $this from the global exception handler, which is not a member of any class. Strangely the call somehow still ended up making its way to the actual member function I wanted to call, but I'm guessing there must be some strange fallback logic PHP was doing to find the "best match" for the function call and in that logic the parameters ended up getting converted to strings somehow.
Anyhow I have ended up just taking a different approach and it's no longer a problem. I still have no idea what was going on though, so if there are any PHP pros out there who can enlighten me I'd still be happy to learn.
I'm currently trying to write some basic unit tests for a php application, unfortunately the test always succeed, even if i want them to fail. I googled for many hours, but without success. Below you can find the code which succeeds on every call:
public function testCreateArticle()
{
$articleRepository = RepositoryFactory::getArticleRepository();
$this->fail();
}
Test succeeds.
If I switch the statements (fail() first) the test fails, but since I need the articleRepository, I can't do any asserts at all. It just seems to return a success after the first line.
Does anyone have a clue what could be wrong?
I have a couple of really basic tests written in PHPUnit and for some reason when I enable one of the assertions, I get "No Tests Executed."
I'm not a skilled unit tester, so it's clearly something I'm doing wrong, but I'm having a hard time tracking down a solution.
I'm testing for a string coming back from a Soap server it's either "true" or "false."
In my unit test if I write this
$hasErrors = 'false';
$this->assertTrue('true' == $hasErrors);
I get "No tests executed!"
If I do the following - I know it's not the same test but it is successful and PHPUnit reports it as successful - I'm just curious why this one runs the tests, while that previous doesn't just show a failure but says no test are executed.
$hasErrors = 'false';
$this->assertFalse('true' == $hasErrors);
I would like the failure to fail rather say "No tests executed."
The same thing happens if I use assertNotEquals rather than assertFalse.
More information. I might have stumbled across a phpunit bug when dealing with a text string "true." I think php unit is wanting to treat it as a boolean rather than a string. So I made some code changes to work with booleans.
$result = $xmlresponse->xpath('//result');
$hasErrors = (string) $result[0]->hasErrors;
if ($hasErrors == 'true') {
$errors = TRUE;
} else {
$errors = FALSE;
}
$this->assertFalse($errors);
Now I get.
PHP Fatal error: Uncaught Failed asserting that true is false.
Why do I need to "catch" this failed asserting? Shouldn't phpunit just report that the test failed?
I'm executing phpunit like this from cli.
phpunit --verbose --debug --configuration testSuite.xml
testSuite.xml looks like this:
<phpunit>
<testsuites>
<testsuite name="connector">
<file>TestNewAccount.class.php</file>
<file>TestModifyAccount.class.php</file>
</testsuite>
</testsuites>
</phpunit>
Update
So I guess my expectations of what PHPunit does out the box are not valid. I expected that phpunit would run the tests, report success and failures and that's that. But apparently it reports successes and throws fatal exceptions on an assertion failure. I don't understand why it's so heavy handed with failures and why it doesn't simply report the failure without me having to catch exceptions in my tests and handle it on my own.
I'm sure I'm still missing something, but for now, I'm not super impressed with phpunit out of the box. I guess it works but it seems to make me work harder than I want to in order to write a few simple tests and assertions.
Update 2
So I'm getting the response from phpunit that I was originally expecting. Now the failures are reporting as failures. I'm not sure what I'm doing differently now than I was before. Now I feel like I'm just cluttering up Stackoverflow with my own senseless rambling. Thanks for the help.
It's good practice to use a quite specific test - assertNotEquals('x', 'y') rather than assertFalse('x'=='y') - having to think about one thing is better than having to then also translate that to a different condition.
When I create a new test class, I tend to put a couple of sanity-checks in, to make sure the test itself is being run, something as simple and obviously failing as 'assertTrue(false)'. If that doesn't fail - then there is something very wrong going on. I've often found it to be name (even upper/lower-case) related.
To debug what is going on, I'd try to get down to the simplest, smallest possible that that does not do what you expect. Debug it from there, or have someone else take a look. The "other person" could equally be a Rubber Duck that you talk it through to, step, by step.
I figured this out. It had nothing to do with PHPUnit as I began to suspect. There's just no way this is only happening to me and it be PHPUnit's fault. I'm doing anything remarkable with PHPUnit.
The problem was that I am making curl calls that had too short of a timeout set. The timeout was set to 10 seconds, but the service I was hitting needed like 2 minute wait times from time-to-time (it's a machine-to-machine sort of thing, so not a huge deal). The short timeout was being hit and PHPUnit would report No Tests Executed!
I have read articles upon articles trying to understand what exceptions are used for in php and I have gone through the answers already given in the forum. One of the answers which made atleast some sense to me is this one: Are exceptions in php really that useful?
Here is a simple function for finding the inverse of a integer with and without using exceptions (source):
With exception:
function inverse($x) {
if ($x==0) {
throw new Exception('Division by zero.');
} else {
return 1/$x;
}
}
try {
inverse();
}
catch (Exception $e) {
echo $e->getMessage();
}
Without exception:
function inverse($x) {
if ($x==0) {
echo "I'm zero. Don't let me be the denominator.";
} else {
return 1/$x;
}
}
So here is my question, why and when should I use one over the other?
why and when should i use one over the other?
Oh, this is easy: You should never use "without exception" :) Don't misuse return values as status flag. Thats a bad habit from earlier days and only makes things more complicated, because then you have to check the return values and even their types over and over again.
If you have a function like inverse() the only thing it should ever do is to "inverse". If it can't do it, it's an exceptional situation, thus (you may guess) an exception.
To sum it up: Throw an exception, when there is a situation, that prevent a function/method to work properly, and that the function/method is not able to handle itself.
There are various opinions on "when to use an exception". My personal opinion is:
If you are working with your own code, theres basically no need to throw exceptions, as you then need to write your own handler for it - which also can be done without throwing an exception.
If you are developing APIs that other programmers are using, it can be usefull to throw exceptions, so the developer using your code knows, that he has to take care of handling errors, AND gets an idea of what was the error-reason. (instead of just getting null he might catch NumberToSmallException, NotANumberException, ....)
In other words: When you already know how to handle an exception if it would appear - dont throw it. If the handling should be up to another developer, using your code - throw it.
Exceptions should not be used to control the flow of your application logic. Therefore use if / else statements.
But these are just my ten cents.
Especially when you use object oriented programming, exceptions are quite handy. For example, in an application where you use a DB library that throws exceptions for when it cannot make a connection. In that case, you can catch that exception somewhere, and you show a special page that tells the user that the database is not working.
Maybe the best usage of Exceptions happens when there a method calls more than one level.
Think like I call method A, then it calls method B, and it calls method C. When this happens, if you do not use exceptions, method A must know all different types of error messages of method B. And method B must know about C's in the same way. But by using exception, method C's error can be caught easily without the help of method A and B.
Exceptions should be used when your script encounters an error, in the example you can't divide by zero and so you have a logical error, so an exception would be appropriate.
Using exceptions allows you to see better errors messages and will help when it comes to debugging, rather than simply printing out a string which could be anything. Furthermore you can catch exceptions so you can detect when something goes wrong, whereas simply outputting a string isn't of much help.
Check out the PHP docs on this for more info.
Exceptions are an invaluable tool when writing complex and/or extensible pieces of software, but saying that return values aren't good for reporting anomalies is IMHO an oversimplified and even dogmatic approach.
In this specific case it's perfectly reasonable to return a null value, as in "the inverse of the argument does not exist". For me the most important point is that inverse does not actually do anything; it merely provides some information (i.e. it is "read-only", it has absolutely no side effects).
Note that "absolutely no side effects" is also a good rule of thumb which means that you should definitely not echo from within the function unless echoing is why it exists in the first place.
If there were an expectation that after calling inverse successfully the state of the program would have changed and inverse cannot perform this change for whatever reason (perhaps it got passed bad arguments; perhaps a resource it needs is not available; etc) then you should absolutely throw an exception and let the caller decide how to handle the error.
Think of it like this:
Sometimes, the value for $x comes from a user (eg. from an HTML form or something), in this case you would like to display an error (maybe something like "The frobing level needs to be different than zero").
Other times, you are getting the value from a database, in that case it's kind of useless to tell the user about frobing levels or stuff like that, you will want to show an error page and log detailed information somewhere on the server (or even send an email to an admin).
With the second example it's not really possible to control what happens in case of an error (the same message is printed each time).
The right thing to do is to let the code that is calling your function decide what happens in case of an error. Exceptions are one way of doing this.
There are 2 major benefits of using exceptions:
They go through the execution stack (meaning that if you have a few nested functions, you don't have to re-pass the error value, this is done automatically.
The first piece of code after a throw() statement is the code in a catch() statement. This means that you don't have to make hundreds of checks in every nested function/method you have.
Considering this functionality, using a return value is useful in simple cases (for example your case). In complex cases, where you have 10-20-30 different error messages that can appear in different levels in the execution stack, using exceptions is a must, or other developers(/even you in a few months) will have major problems when debugging.
That's my 2 cents on the issue, hope it helps.
PS: It's useful to log the exceptions in an exceptions.log.
There is something weird going on in my code so i have to ask.
I have a part of a test:
public function testGetAddresses()
{
//$this->markTestIncomplete('Not implemented yet');
$this->assertTrue($this->_prs->getAddresses() instanceof Crm_Collection);
}
This test fails.
But when I do this:
if ($entity->getAddresses() instanceof Crm_Collection) {
echo "TRUE!";
} else {
echo "FALSE!";
}
It outputs TRUE!
Anybody knows what is going on or might this be a bug in phpunit?
Thanks!
I doubt this is a PHPUnit's bug.
Since you call getAddresses() method on two different objects I guess that in test that fails this method really returns something which is not Crm_Collection.
Is there a chance that getAddresses() method could return null or throw an exception?
Why vadimbelyaev said:
I don't think it's an issue with phpunit, doublecheck your code.
Additionally you can use:
$this->assertType("Classname", $object)
so you get a nice error in case it fails.
(Phpunit will tell you "expected class, got null" instead of "expected true, got false" with helps a lot while debugging :) )
Are other tests OK? Do you run the tests from a browser?
When you run PHP code from commandline I strongly recommend to set a correct path to php.ini. Otherwise PHP will use default values which might be different from your current php.ini
Not sure if this will solve your trouble but it's good to know. Once I spend couple of hours before I found this out.
php -c "c:/program files/apache software foundation/Apache2.2/" -f /path/to/your/script.php