tags:

views:

163

answers:

5

How can I tell if return() was called from within the included file. The problem is that include() returns 'int 1', even if return() wasn't called. Here is an example...

included_file_1.php

<?php

return 1;

included_file_2.php

<?php

echo 'no return here, meep';

main.php

<?php

$ret = include('included_file_1.php');

// This file DID return a value, int 1, but include() returns this value even if return() wasn't called in the included file.
if ($ret === 1)
{
    echo 'file did not return anything';
}

var_dump($ret);

$ret = include('included_file_2.php');

// The included file DID NOT return a value, but include() returns 'int 1'
if ($ret === 1)
{
    echo 'file did not return anything';
}

var_dump($ret);

Edit: As a temporary solution, I'm catching the output from include() (from echo/print statements). If any output was produced, I ignore the return value from include().

Not pretty, but it provides the functionality I need in my web app/framework.

+1  A: 

Good question. Looking at the examples in the manual, I guess you can't.

The best workaround idea that comes to mind is to make all your includes in your project not return naked values, but an array containing the return value (return array(1);).

Everything else that comes to mind (mine at least) involves defining some constants or variables to flag whether you're in an include or not. Nothing elegant.

Pekka
A: 

If there is nothing to return in the included file, then the include function returns 1 by default. Otherwise it will return whatever is sent by the included file. Echo and print statements are not a return, it has to be the 'return' statement designated by PHP. Everything else will be processed normally. This code is basically saying, 'did the file execute properly?' and it's returning 1, 'yes it did.'

PHP: include - Manual - Take a look at "Handling Returns" right below the security warning messages and then look at Example 5 and the text right below it. It explains it all perfectly.

animuson
Yes, but if the script is included, include() will return the value passed to return() in the included file OR 'int 1' to indicate a successful include. So, when include() returns 'int 1', I can't tell if it is a return value from the included file or include().
John Himmelman
Nonsense. If you KNOW that the file returns a value of it's own then you can assume that the value is the value you wanted it to return. Include will never override your return value to send 1 that it completed. This is about you knowing exactly what your files do and what values come out of them. If you know your file doesn't return anything, then the value should always be 1.
animuson
Animuson: Yes, but I don't know what other peoples file's are doing. There will also be edge cases that popup that will break the framework, and will be a pita for anyone else to debug.
John Himmelman
Checking for output doesn't solve the problem though. What if they send output and a valid return value? Then the return value gets ignored? You're right, you don't know what your users are going to put into their files, but it IS the responsibility of programmer using your framework to learn exactly what they're doing and read documentation before they start messing with things. If your entire framework can break from a return value, you need to reconsider your framework.
animuson
animuson: The include()'d file essentially represents a single action of a module's controller. If the file returns a value, the value is formatted into the correct response type (ie, json, xml, etc...). If output is produced from within the action file, the output is templated for standard web presentation. I don't want to rely on the action script producing output, and it can break if white-spaces are accidentally output, but I don't have any alternatives (that don't involve backtraces or reflection).
John Himmelman
A: 

This behavior is by design - the include statement returns 1 when the include is successful (or the value return'ed by the included file), as script execution can continue even if an include fails and a programmer might what to check for this case.

From the manual:

[the return value] is 1 because the include was successful. Notice the difference between the above examples. The first uses return() within the included file while the other does not. If the file can't be included, FALSE is returned and E_WARNING is issued.

In this case, simply don't use 1 in your code as a return value for a file, i.e., this return value is effectively reserved for use by the PHP include statement.

pygorex1
This stinks, then I won't be able to gracefully handle the output :(. I guess my only alternative is to check if include() produced any output (echo/print). If it did, then I'll ignore the return value.
John Himmelman
A: 

$ret = include('...'); Will always return 1 if the file exists.

Try creating a variable and check if it is set.

include_file_1.php

<?php
$includeFile1 = true;

main.php

<?php
include('included_file_1.php');

if (isset($includeFile1) == true) 
{
    echo "It was included";
}
Brant
+1  A: 

You could probably make use of debug_backtrace(), but it's not really an ideal solution. It's slow, and you'd have to do a lot of work to get the results you wanted.

Unfortunately, the situation you describe falls outside the regular usage of include and return. I would simply alter your logic to work with it. Why not have files that usually don't call return at the end simply call return 2? That way you would get a value that still evaluates to true on normal comparisons, but you could use it as a distinction between the other return 1 calls.

zombat
Great idea with `debug_backtrace` - didn't think of that. However, I don't think it will work, as the included file will not leave any trace (no pun intended) in the backtrace when called after the include.
Pekka
Zombat: Great advice but I debug_backtrace() skips over the include() and not into. But, I could use eval() to execute the code, with an appended debug_backtrace(). But that approach is too messy and can cause other, harder to debug, edge cases. Sad day :(.
John Himmelman