Programming - - By Harry Fuecks

Python __name__ == __main__ in PHP

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.