There is nothing wrong here per se. However w3coded so learn if one page request happens to include 15 w3coded so learn similar classes. You are running require_once 15 w3coded so learn times, or for a nice visual:,But now what if a w3coded so learn visitor is browsing the site and not even logged w3coded so learn in and the framework loads: w3coded so learn require_once("includes/user.php"); for every w3coded so learn single request.,when top-level require_once is w3coded so learn mixed with conditional require_once, this can w3coded so learn result in code that is uncacheable by opcode w3coded so learn caches such as APC, which will be bundled with w3coded so learn PHP 6.,The use of require_once() technically w3coded so learn affects performance for running that function 14 w3coded so learn times, on top of having to parse those w3coded so learn unnecessary lines. With just 10 other highly w3coded so learn used classes with that similar problem, it could w3coded so learn account for 100+ lines of such rather pointless w3coded so learn repetitive code.
If you are doing thousands of *_once
, you could do the work yourself in a lighter fashion. For simple apps, just making sure you've only included it once should suffice but if you're still getting redefine errors, you could something like this:
if (!defined('MyIncludeName')) {
require('MyIncludeName');
define('MyIncludeName', 1);
}
I'll personally stick with the *_once
statements but on silly million-pass benchmark, you can see a difference between the two:
php hhvm
if defined 0.18587779998779 0.046600103378296
require_once 1.2219581604004 3.2908599376678
<?php // test.php
$LIMIT = 1000000;
$start = microtime(true);
for ($i=0; $i<$LIMIT; $i++)
if (!defined('include.php')) {
require('include.php');
define('include.php', 1);
}
$mid = microtime(true);
for ($i=0; $i<$LIMIT; $i++)
require_once('include.php');
$end = microtime(true);
printf("if defined\t%s\nrequire_once\t%s\n", $mid-$start, $end-$mid);
<?php // include.php
// do nothing.
I started out by creating 100 header files that used require_once to include another header file. Each of these files looked something like:
<?php
// /home/fbarnes/phpperf/hdr0.php
require_once "../phpperf/common_hdr.php";
?>
I created these using a quick Bash hack:
for i in /home/fbarnes/phpperf/hdr{00..99}.php; do
echo "<?php
// $i" > $i
cat helper.php >> $i;
done
This way I could easily swap between using require_once and require when including the header files. I then created an app.php to load the one hundred files. This looked like:
<?php
// Load all of the php hdrs that were created previously
for($i=0; $i < 100; $i++)
{
require_once "/home/fbarnes/phpperf/hdr$i.php";
}
// Read the /proc file system to get some simple stats
$pid = getmypid();
$fp = fopen("/proc/$pid/stat", "r");
$line = fread($fp, 2048);
$array = split(" ", $line);
// Write out the statistics; on RedHat 4.5 with kernel 2.6.9
// 14 is user jiffies; 15 is system jiffies
$cntr = 0;
foreach($array as $elem)
{
$cntr++;
echo "stat[$cntr]: $elem\n";
}
fclose($fp);
?>
I contrasted the require_once headers with require headers that used a header file looking like:
<?php
// /home/fbarnes/phpperf/h/hdr0.php
if(!defined('CommonHdr'))
{
require "../phpperf/common_hdr.php";
define('CommonHdr', 1);
}
?>
Before opening a file from require_once the following system calls are made:
time(NULL) = 1223772434
lstat64("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf/h", {st_mode=S_IFDIR|0755, st_size=270336, ...}) = 0
lstat64("/home/fbarnes/phpperf/h/hdr0.php", {st_mode=S_IFREG|0644, st_size=88, ...}) = 0
time(NULL) = 1223772434
open("/home/fbarnes/phpperf/h/hdr0.php", O_RDONLY) = 3
This contrasts with require:
time(NULL) = 1223772905
lstat64("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf/h", {st_mode=S_IFDIR|0755, st_size=270336, ...}) = 0
lstat64("/home/fbarnes/phpperf/h/hdr0.php", {st_mode=S_IFREG|0644, st_size=146, ...}) = 0
time(NULL) = 1223772905
open("/home/fbarnes/phpperf/h/hdr0.php", O_RDONLY) = 3
Tech Your Universe implies that require_once should make more lstat64 calls. However, they both make the same number of lstat64 calls. Possibly, the difference is that I am not running APC to optimize the code above. However, next I compared the output of strace for the entire runs:
[fbarnes@myhost phpperf]$ wc -l strace_1000r.out strace_1000ro.out
190709 strace_1000r.out
210707 strace_1000ro.out
401416 total
Effectively there are approximately two more system calls per header file when using require_once. One difference is that require_once has an additional call to the time() function:
[fbarnes@myhost phpperf]$ grep -c time strace_1000r.out strace_1000ro.out
strace_1000r.out:20009
strace_1000ro.out:30008
The other system call is getcwd():
[fbarnes@myhost phpperf]$ grep -c getcwd strace_1000r.out strace_1000ro.out
strace_1000r.out:5
strace_1000ro.out:10004
This is called because I decided to relative path referenced in the hdrXXX files. If I make this an absolute reference, then the only difference is the additional time(NULL) call made in the code:
[fbarnes@myhost phpperf]$ wc -l strace_1000r.out strace_1000ro.out
190705 strace_1000r.out
200705 strace_1000ro.out
391410 total
[fbarnes@myhost phpperf]$ grep -c time strace_1000r.out strace_1000ro.out
strace_1000r.out:20008
strace_1000ro.out:30008
Take the example of using require_once()
at the top of every class as seen in many libraries:
require_once("includes/usergroups.php");
require_once("includes/permissions.php");
require_once("includes/revisions.php");
class User{
// User functions
}
The other ways it can be misused, is when a class is re-used by many others!
Say you have about 50 classes that use helper
functions. To make sure helpers
are available for those classes when they are loaded, you get:
require_once("includes/helpers.php");
class MyClass{
// Helper::functions(); // etc..
}
There is nothing wrong here per se. However if one page request happens to include 15 similar classes. You are running require_once
15 times, or for a nice visual:
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
Last Update : 2023-09-22 UTC 12:32:58 PM
Last Update : 2023-09-22 UTC 12:32:50 PM
Last Update : 2023-09-22 UTC 12:32:34 PM
Last Update : 2023-09-22 UTC 12:32:21 PM
Last Update : 2023-09-22 UTC 12:32:12 PM
Last Update : 2023-09-22 UTC 12:31:42 PM
Last Update : 2023-09-22 UTC 12:31:25 PM