One of those nice features of Python, that marks it as a language designed for developers (as opposed to one designed for tool vendors) is the ability to conditionally run some logic if you’re executing a script directly but ignore it if the script is being imported (”included”) by another script.
For example;
class User:
def setName(self, name):
self.name = name
def getName(self):
return self.name
# Only execute this we're "main"...
if __name__ == "__main__":
u = User()
u.setName("Harry")
print u.getName()
The code after the ‘if __name__ == “__main__”:’ is only executed is I run this script directly. If I import the User class from another script it is ignored.
Makes a very handy tool for testing (or better yet unit testing) a Python script. So much so I want it in PHP.
One trick to do so is like this;
name = $name;
}
function getName() {
return $this->name;
}
}
if ( realpath(__FILE__) == realpath($_SERVER['SCRIPT_FILENAME']) ) {
$u = & new User();
$u->setName("Harry");
print $u->getName();
}
?>
This relies on the predefined constant __FILE__ which gets populated with the name of script where __FILE__ is accessed (i.e. it works irrespective of includes). The value of __FILE__ should be unique to the script, as far as I know.
There’s two problems here though. First if you use this approach alot, there’s going to tons of calls to realpath(), meaning a performance hit. Also $_SERVER['SCRIPT_FILENAME'] returns the name of the PHP executable when using PHP via CGI and otherwise probably can’t be relied upon on web servers other than Apache.
Another approach would be to conditionally define a constant using the value of __FILE__ e.g.;
class User {
// ....
}
if ( !defined('__MAIN__') ) {
define ('__MAIN__',__FILE__);
}
if ( __FILE__ == __MAIN__ ) {
$u = & new User();
$u->setName("Harry");
print $u->getName();
}
If the constant __MAIN__ hasn’t already been defined (by a script which included this one), it gets assigned the value of __FILE__ and the conditional code block is executed.
This approach is probably most trustworthy in that it should work on any PHP install but requires additional work and if you forget to define __MAIN__ somewhere you may end up with code being executed that you weren’t expecting.
Note that the following;
@define ('__MAIN__',__FILE__);
The @ operator, used to suppress the error notice if __MAIN__ was already defined, is slower than using is_defined().
The third option, which I’m not sure I 100% trust to work correctly everywhere, is to use get_included_files() like;
class User {
// ...
}
if ( __FILE__ == array_shift(get_included_files()) ) {
$u = & new User();
$u->setName("Harry");
print $u->getName();
}
This is based on the assumptions that the file where execution began will always be the first element in the list returned by get_included_files() (which, as far as I know, it should be) and that it will match the value of __FILE__. So long as this script wasn’t included (or required) by any other, the code inside the if condition is executed.
Of course the overall approach comes cost of parsing the code inside the condition, which can only be avoided using a OPCODE cache like the Zend Accelerator but it makes a useful tool when you’re building modular code and want to develop and test “modules” in your app without running the entire application.
Related posts:
- How to Use PHP Namespaces, Part 1: The Basics In the first part of a series of articles, Craig...
- Introducing php-tracer-weaver php-tracer-weaver is a tool for automatically generating docblock comments, with...
- Server-side JavaScript Will Be as Common as PHP Despite the fact that JavaScript has been typecast as the...
- How to Use PHP Namespaces, Part 3: Keywords and Autoloading In the final part of his series explaining PHP namespaces,...
- Build a Buzzword Bingo Card in PHP Bored in meetings? Worry no longer. Raena demonstrates how to...







There is an another solution:
if (basename(__FILE__) == basename($_SERVER['PHP_SELF'])) { // ... }It only requires that the included file has an unique name.
April 28th, 2004 at 4:13 am
And another one:
if (count(debug_backtrace()) == 0) { echo 'SELF'; }But I didn’t do any perfomance tests with debug_backtrace() so don’t know if it is not to slow.
April 28th, 2004 at 5:04 am
if (count(debug_backtrace()) == 0) {Nice one! Think that wins the lateral thought of the day ;)
Running it through XDebug, compared to the alterative;
if ( __FILE__ == array_shift(get_included_files()) ) {The results looks like;
Total Time Avg. Time #Calls Function Name 0.1426506042 0.0000014265 100000 count 0.1460983753 0.0000014610 100000 debug_backtracevs.
Total Time Avg. Time #Calls Function Name 0.1719875336 0.0000017199 100000 array_shift 0.1729249954 0.0000017292 100000 get_included_filesLooks like debug_backtrace is the winner.
April 28th, 2004 at 11:21 am
I think is_defined() should be a typo only, but I report it.
The name of the desired function is defined().
April 28th, 2004 at 5:03 pm
heh, Harry, we think alike.
I emailed, dmitry (The developer of the Perl extension) earlier, about implementing Python and I just found your post :p. Also a comment on zend refered to this as ‘bloatware’, which didn’t quite make sense considering its not bundled with PHP. http://www.zend.com/zend/comments/show_comment.php?article=php5-perl&id=4887&pid=4751&days=10000&f_id=php5-perl&mode=&kind=php5
April 29th, 2004 at 6:25 pm
What are your comments about the perl/python extension being ‘bloatware’?
April 29th, 2004 at 6:27 pm
Well the comment “Completly useless… just bloatware” doesn’t really give anything to argue against, accept to say “No it isn’t”. Seems more like random spam.
To date I’ve never played with the Python or Perl extensions.
Where the subject of “bloat” might need examining is when it comes to the performance overhead of loading / executing external Perl/Python code.
But there is most definately a value in being able to execute Perl / Python code in PHP. Just head to CPAN and you have your answer. Python also has some excellent libraries.
Also that this has got Dmitry’s name on it suggests to me it’s a serious project, Dmitry being the original author of Turck MMCache and now the SOAP extension.
April 30th, 2004 at 3:47 am
[...] The link doesn’t quite raise the full story though. As I remember, with PHP as a CGI under Apache, $_SERVER[’SCRIPT_FILENAME’] is the path to the CGI executable, not the script it is executing—that relates to a request for a PHP constant called __MAIN__ to identify the script where execution began. [...]
November 9th, 2005 at 6:53 am