fb.module tries to include facebook-php-sdk and if it's not found a error is thrown. This is ok except that the error from failed include also gets returned.

So instead of:
Failed to find the Facebook client libraries at sites/all/libraries/facebook-php-sdk/src/facebook.php. Read the README.txt and follow the instructions carefully.

you get:
Failed to find the Facebook client libraries at sites/all/libraries/facebook-php-sdk/src/facebook.php. Read the README.txt and follow the instructions carefully.
Warning: include(sites/all/libraries/facebook-php-sdk/src/facebook.php) [function.include]: failed to open stream: No such file or directory in fb_api_init() (line 422 of /home/devel/hannes/sites/all/modules/fb/fb.module).
Warning: include() [function.include]: Failed opening 'sites/all/libraries/facebook-php-sdk/src/facebook.php' for inclusion (include_path='.:/usr/local/lib/php:/usr/local/lib/php/PEAR') in fb_api_init() (line 422 of /home/devel/hannes/sites/all/modules/fb/fb.module).
Failed to find the Facebook client libraries at sites/all/libraries/facebook-php-sdk/src/facebook.php. Read the README.txt and follow the instructions carefully.

So my suggestion is to use @ before the include. While this is normally considered a ugly method, in this case the problematic code is allready inside try block.

Comments

hkirsman’s picture

StatusFileSize
new702 bytes

Patch included.

thedavidmeister’s picture

Status: Active » Needs review

That patch seems reasonable enough. Setting to "needs review" so that hopefully Dave can commit it soon.

dresde’s picture

Hi,

I've never dealt with a patch for a module. How do I use it? Which file should I edit to add that?

Thanks

hkirsman’s picture

You can apply it manually or automatically.

Manually
If you read the patch you see changes are in fb.module and on line 419 (I'm not sure if it's the line where function fb_api_init($fb_app) { is or the line what you need to replace but anyways look there). Look for what lines have - and +. - states what was removed and + states what the removed line was replaced with.

Automatically
You need to have git repository set up for this module first (7.x-3.x-dev as written above my first post). So here http://drupal.org/project/fb/git-instructions choose 7.x.3.x and execute the git command written below. It's
git clone --recursive --branch 7.x-3.x http://git.drupal.org/project/fb.git
for fb module. Copy patch into fb module dir. Finally execute
git apply fb-catch_a_failed_include-1804172-1.patch
or
git am fb-catch_a_failed_include-1804172-1.patch
Both commands apply patch but are somewhat different. Here's a more in-depth help: http://ariejan.net/2009/10/26/how-to-create-and-apply-a-patch-with-git or try just http://www.google.ee/search?q=apply+patch+git&aq=f&sugexp=chrome,mod=1&s...

Maby you want to create a patch yourself. First linke here http://www.google.ee/search?q=apply+patch+drupa&sugexp=chrome,mod=1&sour... tells you how. In short it's it's
git diff > [project_name]-[short_description]-[issue-number]-[comment-number].patch

Dave Cohen’s picture

Component: I am lazy and not paying attention » Code
Assigned: Unassigned » Dave Cohen
Status: Needs review » Reviewed & tested by the community

I had been under the impression that PHP's @ was a performance hit. But maybe not: http://seanmonstar.com/post/909029460/php-error-suppression-performance

I will get this in there. Thanks

hkirsman’s picture

Good to know!

I rewrote the tests to see what we could do better in fb.module. I managed to get 4x better results if is_file was used.

Check it out yourself.


function no_suppress() {
  $fb_platform = 'i_dont_exist';
  if (!(is_file($fb_platform) && include($fb_platform) && class_exists('Facebook'))) {
  }
}

function suppress() {
  $fb_platform = 'i_dont_exist';
  if (!class_exists('Facebook') && !@include($fb_platform)) {

  }
}

function do_test($suppress = false, $loops = 1000000) {
    if($suppress) {
        echo "starting suppress...\n";
        $start = microtime(true);
        for($i = 0; $i < $loops; $i++) {
            suppress();
        }
        $end = microtime(true);
    } else {
        echo "starting no_suppress...\n";
        $start = microtime(true);
        for($i = 0; $i < $loops; $i++) {
            no_suppress(true);
        }
        $end = microtime(true);
    }
    echo "ended: " . ($end - $start) . "\n";
}

do_test(1, 20000);
echo '<br>';
do_test(0, 20000);

Didn't have time to test it on fb.module

hkirsman’s picture

Status: Reviewed & tested by the community » Needs review
thedavidmeister’s picture

is_file() is a cached system stat, so that test isn't quite right. You need to explicitly clear the stat cache to test the "raw" performance of is_file() vs other functions in that style of profiling.

ie. add clearstatcache() to the no_suppress test.

http://stackoverflow.com/questions/4099103/is-file-file-exists-performan...

hkirsman’s picture

Good point!

I didn't get any loss in speed when clearstatcache() was enabled. Not on server or my pc.

clearstatcache() enabled:
starting suppress... ended: 23.215982913971
starting no_suppress... ended: 1.550351858139

clearstatcache() disabled:
starting suppress... ended: 27.163813114166
starting no_suppress... ended: 1.5654368400574

Last tests were run on my pc and 20 000 times. Current tests were run 1 000 000 time and on server.

At some runs suppressed result got even 56.331800222397 when no_suppress was always under 2.

I guess error throwing really is as bad as it's said.

function no_suppress() {
  $fb_platform = 'i_dont_exist';
  clearstatcache();
  if (!(is_file($fb_platform) && include($fb_platform) && class_exists('Facebook'))) {
  }
}

function suppress() {
  $fb_platform = 'i_dont_exist';
  if (!class_exists('Facebook') && !@include($fb_platform)) {

  }
}

function do_test($suppress = false, $loops = 1000000) {
    if($suppress) {
        echo "starting suppress...\n";
        $start = microtime(true);
        for($i = 0; $i < $loops; $i++) {
            suppress();
        }
        $end = microtime(true);
    } else {
        echo "starting no_suppress...\n";
        $start = microtime(true);
        for($i = 0; $i < $loops; $i++) {
            no_suppress(true);
        }
        $end = microtime(true);
    }
    echo "ended: " . ($end - $start) . "\n";
}

do_test(1);
echo '<br>';
do_test(0);
hkirsman’s picture

StatusFileSize
new1.07 KB

Patch attached. I also fixed the error repeat (although weird that it's called twice).

thedavidmeister’s picture

Status: Needs review » Reviewed & tested by the community

I'm not surprised that is_file() is faster than suppressing errors. Although, if you had a remote filesystem that might be a different situation.. or maybe not. Anyway, I like this patch better; it makes total sense :)

Dave Cohen’s picture

Status: Reviewed & tested by the community » Needs review

I'm curious about clearstatcache. In an apache environment, does the stat cache persist across multiple requests? If so, I don't think our test should clear it.

But more importantly, your PHP test is really testing how long it takes to handle an include error. Not just how long it takes to suppress errors. I'm more concerned about the case when the file is found. The case where the file is not found can be dog slow, it shouldn't be the normal case.

I changed the test to include "i_exist" and looks to me like the supress is way better than the is_file()...

[dave@archX60 devel]$ ls -l
total 8
-rw-r--r-- 1 dave dave   6 Oct 15 11:58 i_exist
-rw-r--r-- 1 dave dave 815 Oct 15 11:58 test_1804172.php
[dave@archX60 devel]$ php test_1804172.php 
starting suppress...
ended: 59.872272968292
<br>starting no_suppress...
ended: 178.17403697968

Here's what I used:

<?php
function no_suppress() {
  $fb_platform = 'i_exist';
  clearstatcache();
  if (!(is_file($fb_platform) && include($fb_platform))) {
  }
}

function suppress() {
  $fb_platform = 'i_exist';
  if (!class_exists('Facebook') && !@include($fb_platform)) {

  }
}

function do_test($suppress = false, $loops = 1000000) {
    if($suppress) {
        echo "starting suppress...\n";
        $start = microtime(true);
        for($i = 0; $i < $loops; $i++) {
            suppress();
        }
        $end = microtime(true);
    } else {
        echo "starting no_suppress...\n";
        $start = microtime(true);
        for($i = 0; $i < $loops; $i++) {
            no_suppress(true);
        }
        $end = microtime(true);
    }
    echo "ended: " . ($end - $start) . "\n";
}

do_test(1);
echo '<br>';
do_test(0);
Dave Cohen’s picture

Commented out the clearstatcache, and ran it one more time:

[dave@archX60 devel]$ php test_1804172.php 
starting suppress...
ended: 75.664173126221
<br>starting no_suppress...
ended: 153.97479200363

Supressing errors wins, right?

thedavidmeister’s picture

hmmm that's a good point about not optimising the case where things fail.. clearing the stat cache would help get the "raw" speed of is_file() which I think is reasonably fair because you're not including the files 1000000 times on a page load.

Do you have APC enabled on your test server? that might make a difference to the speed of the cached is_file()?

Dave Cohen’s picture

Status: Needs review » Fixed

Finally pushed the change which suppresses the error. Thanks again!

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.