是否有任何优雅的方法来检查是否使用
include
/include_once
/require
/require_once
包含文件,或者页面是否实际上是直接加载的?我正在尝试在创建类文件时在类文件内设置一个测试文件。
我正在寻找类似于 Python 的
if __name__ == "__main__":
技术。无需设置全局变量或常量。
引自:如何知道php脚本是否通过require_once()被调用?
我正在寻找一种方法来确定文件是否已被包含或直接调用,所有这些都来自文件内部。在我的探索中的某个时刻,我经历了这条线索。从 PHP 手册中检查此网站以及其他网站和页面上的各种其他线程,我得到启发并想出了这段代码:
if (basename(__FILE__) == basename($_SERVER["SCRIPT_FILENAME"])) {
echo "called directly";
} else {
echo "included/required";
}
本质上,它比较当前文件的名称( 可以包含)与正在执行的文件相同。
信用:@Interwebs Cowboy
您可以通过 get_included_files 执行此操作 — 返回一个包含包含或所需文件名称的数组,并根据
__FILE__
进行验证
我很欣赏所有的答案,但我不想在这里使用任何人的解决方案,所以我结合了你的想法并得到了这个:
<?php
// place this at the top of the file
if (count(get_included_files()) === 1) define ('TEST_SUITE', __FILE__);
// now I can even include bootstrap which will include other
// files with similar setups
require_once '../bootstrap.php'
// code ...
class Bar {
...
}
// code ...
if (defined('TEST_SUITE') && TEST_SUITE === __FILE__) {
// run test suite here
}
?>
if (defined('FLAG_FROM_A_PARENT'))
// Works in all scenarios but I personally dislike this
if (__FILE__ == get_included_files()[0])
// Doesn't work with PHP prepend unless calling [1] instead.
if (__FILE__ == $_SERVER['SCRIPT_FILENAME'])
// May break on Windows due to mixed DIRECTORY_SEPARATOR
if (basename(__FILE__) == basename($_SERVER['SCRIPT_FILENAME']))
// Doesn't work with files with the same basename but different paths
if (realpath(__FILE__) == realpath($_SERVER['SCRIPT_FILENAME']))
// Seems to do the trick as long as document root is properly configured
注意:在 WAMP 服务器上,虚拟主机有时会继承默认文档根目录设置,导致
$_SERVER['DOCUMENT_ROOT']
显示错误的路径。
get_included_files()
返回数组,其中 0 索引表示第一个“包含”文件。因为直接运行在本术语中意味着“包含”,所以您可以简单地检查第一个索引是否等于 __FILE__
:
if(get_included_files()[0] == __FILE__){
do_stuff();
}
这在 PHP 4 上不起作用,因为 PHP 4 没有在该数组中添加运行文件。
<?php
if (__FILE__ == $_SERVER['SCRIPT_FILENAME'])
{
//file was navigated to directly
}
?>
取自 mgutt 对一个稍微不同的问题的回答这里。重要的是要注意,如果脚本从命令行运行,则此方法不起作用,但除此之外它的功能与 python 的功能完全相同
if __name__ == '__main__':
据我所知
它们无法将它们分开为
include/include_once/require/require_once
但 php 有 get_included_files
和 get_required_files
,这是相同的东西,只返回所有包含文件的数组。如果它是 required
或 included
,则不会将其分开。
示例
a.php
include 'b.php';
include_once 'c.php';
require 'd.php';
var_dump(get_required_files());
输出
array
0 => string '..\lab\stockoverflow\a.php' (length=46) <---- Returns current file
1 => string '..\lab\stockoverflow\b.php' (length=46)
2 => string '..\lab\stockoverflow\c.php' (length=46)
3 => string '..\lab\stockoverflow\d.php' (length=46)
但是你可以做类似的事情
$inc = new IncludeManager($file);
var_dump($inc->find("b.php")); // Check if a file is included
var_dump($inc->getFiles("require_once")); // Get All Required Once
使用的类
class IncludeManager {
private $list = array();
private $tokens = array();
private $find;
private $file;
private $type = array(262 => "include",261 => "include_once",259 => "reguire",258 => "require_once");
function __construct($file) {
$this->file = $file;
$this->_parse();
}
private function _parse() {
$tokens = token_get_all(file_get_contents($this->file));
for($i = 0; $i < count($tokens); $i ++) {
if (count($tokens[$i]) == 3) {
if (array_key_exists($tokens[$i][0], $this->type)) {
$f = $tokens[$i + 1][0] == 371 ? $tokens[$i + 2][1] : $tokens[$i + 1][1];
$this->list[] = array("pos" => $i,"type" => $this->type[$tokens[$i][0]],"file" => trim($f, "\"\'"));
}
}
}
}
public function find($find) {
$finds = array_filter($this->list, function ($v) use($find) {
return $v['file'] == $find;
});
return empty($finds) ? false : $finds;
}
public function getList() {
return $this->list;
}
public function getFiles($type = null) {
$finds = array_filter($this->list, function ($v) use($type) {
return is_null($type) ? true : $type == $v['type'];
});
return empty($finds) ? false : $finds;
}
}
这是一个不同的想法。 只需在需要时包含该文件即可。 在包含文件中您可以决定是否需要包含以下内容:
<?php
if (defined("SOME_UNIQUE_IDENTIFIER_FOR_THIS_FILE"))
return;
define("SOME_UNIQUE_IDENTIFIER_FOR_THIS_FILE", 1);
// Rest of code goes here
$target_file = '/home/path/folder/file.php'; // or use __FILE__
if ($x=function($e){return str_replace(array('\\'), '/', $e);}) if(in_array( $x($target_file), array_map( $x , get_included_files() ) ) )
{
exit("Hello, already included !");
}
我不认为
get_included_files
是完美的解决方案,如果你的主脚本在检查之前包含一些其他脚本怎么办?我的建议是检查 __FILE__
是否等于 realpath($argv[1])
:
<?php
require('phpunit/Autoload.php');
class MyTests extends PHPUnit_Framework_TestCase
{
// blabla...
}
if (__FILE__ == realpath($argv[0])) {
// run tests.
}
当我遇到这个问题时,我采取了类似的方法。我找到的解决方案是在 include_once 方法中根据需要加载每个文件。希望这有帮助。
$FILES = get_included_files(); // Retrieves files included as array($FILE)
$FILE = __FILE__; // Set value of current file with absolute path
if(!in_array($FILE, $FILES)){ // Checks if file $FILE is in $FILES
include_once "PATH_TO_FILE"; // Includes file with include_once if $FILE is not found.
}
我建立了以下功能来检查加载的文件:
ARRAY_DUMP($FILES);
function ARRAY_DUMP($array){
echo "
<span style='font-size:12px;'>".date('h:i:s').":</span>
<pre style='font-size:12px;'>", print_r($array, 1), "</pre>
";
}
输出:
currentArray
(
[0] => /home/MY_DOMAIN/hardeen/index.php
[1] => /home/MY_DOMAIN/hardeen/core/construct.php
[2] => /home/MY_DOMAIN/hardeen/core/template.php
[3] => /home/MY_DOMAIN/hardeen/bin/tags.php
[4] => /home/MY_DOMAIN/hardeen/bin/systemFunction.php
)