In PHP, when a file is included inside a method, which variables, $this and class members can the included code access?
answer
- same scope as the include line
- locals of the method, not globals
- $this and private members too
- declared functions and classes go global
- namespace, use and strict_types stay per file
basics
~20 sIncluded code runs in the scope of the line that includes it: inside a method it sees that method's local variables, $this and the class's private members, while functions and classes it declares are global.
solid answer
~40 sAn included file does not get its own variable scope. Its code runs in the **scope of the line where the include happens**: at the top level of a script it sees global variables; inside a function or method it sees that function's **local variables**, and variables it creates become locals of that function. Inside a method, the included code also gets `$this` and the class scope, so it can read private properties; that is how plain-PHP templates rendered from a view object work. Two things do not follow the caller: **functions and classes** declared in the file are always global, and **per-file compile settings** such as the `namespace`, `use` imports and `declare(strict_types=1)` belong to the included file itself. Magic constants like `__DIR__` and `__FILE__` also describe the included file.
code
php · 15 lines<?php
declare(strict_types=1);
// greeting.php contains: <?php $message = "Hi, {$name}"; $leaked = true;
$name = 'global';
function greet(): string
{
$name = 'local';
include __DIR__ . '/greeting.php'; // sees the local $name
return $message; // created inside greet()'s scope
}
echo greet(), PHP_EOL; // Hi, local
var_dump(isset($leaked)); // bool(false): stayed local to greet()go deeper
Recall that included code shares the variables available at the include line and can overwrite them.
Explain the difference between including at the top level and inside a function, and that declared functions and classes are always global.
Watch for accidental variable overwrites and hidden template dependencies, and remember that includes inside methods can touch private state.
Limit scope-sharing includes to a narrow rendering layer with explicit inputs, and keep the rest of the codebase on classes, autoloading and returned values.
## Inherited scope, not a new scope PHP functions have their own local variable scope, but an **included file does not**. When `include` or `require` runs, the engine executes the included file's top-level code with the **symbol table of the including code**. In the manual's words, the included code inherits the variable scope of the line on which the include occurs. What that means in practice: | Include happens in | Included code sees | Variables it creates end up in | |---|---|---| | Top level of a script | global variables | the global scope | | A function | that function's local variables | that function's locals | | A method | the method's locals, `$this`, the class scope | the method's locals | Variables that exist only in the global scope stay invisible to code included inside a function, unless the function imports them with `global`, as function scope rules require anywhere else. ## Including inside a method Because the included code runs in the caller's frame, it also receives the caller's **object and class context**: - `$this` refers to the object whose method did the include. - Private and protected members of that class are accessible, because the code runs with that class as its scope. - `self::` and `static::` refer to that class. This is the basis of a common template technique: a `View` object's `render()` method sets up a few local variables and includes a `.php` template, which can then use those variables and `$this->escape(...)` directly. ```php <?php final class View { public function __construct(private string $dir) {} public function render(string $template, array $data): string { extract($data, EXTR_SKIP); // locals for the template ob_start(); include $this->dir . '/' . $template . '.php'; return (string) ob_get_clean(); } private function e(string $s): string { return htmlspecialchars($s, ENT_QUOTES); } } ``` A template that writes `<?= $this->e($title) ?>` works because it runs inside `render()`. ## What is not inherited Some properties belong to a **file**, not to a call frame, and they do not flow into included code: - **Namespace.** Each file declares its own `namespace`; without one, the included file's declarations are in the global namespace, whatever the includer used. - **`use` imports.** Import tables are per file, so the included file must import what it references by short name. - **`declare(strict_types=1)`.** Strict typing is decided by the file that makes a call, so calls written in the included file follow that file's own declaration. - **Magic constants.** `__FILE__`, `__DIR__` and `__LINE__` are fixed when the included file is compiled and describe that file. This is exactly why `__DIR__` is the reliable base for relative paths. ## Declarations are global Functions and classes declared at the top level of an included file are registered **globally** (within the file's namespace), even when the include happens inside a function. They outlive the call that included them, and including the file again fails with "Cannot redeclare". Constants defined with `define()` are also global. ## A step-by-step example Consider `function report(): void { $rows = load(); include __DIR__ . '/report.tpl.php'; }`: 1. `report()` creates the local `$rows`. 2. The template runs in `report()`'s frame, so it reads `$rows` directly. 3. If the template sets `$total`, that becomes another local of `report()`, visible after the include returns. 4. Any function the template declares is global, so rendering the template twice in one request fails with "Cannot redeclare". 5. When `report()` returns, its locals, including those created by the template, are released. ## Risks of inherited scope - **Accidental overwrites.** An included file that assigns `$user` or `$i` silently replaces the caller's variable of the same name. - **Hidden dependencies.** A template that uses `$items` depends on whatever the including code happened to define; nothing declares that contract. - **Private access.** A file included inside a method can read and change private state, so including untrusted or loosely reviewed files there widens the attack and bug surface. - **Harder analysis.** Static analysers cannot always know which variables exist in an included file, so they report them as undefined or skip checks. Containing the include in a small dedicated method, passing data explicitly and returning values instead of sharing variables keeps these risks bounded.
- In PHP, does an included file inherit declare(strict_types=1) from the file that includes it?No. `strict_types` is a per-file setting that governs calls written in that file. An included file without its own `declare(strict_types=1);` makes its calls in coercive mode, even when the includer is strict. Each file that should be strict needs its own declaration as its first statement.
- In PHP, why can a template included from a View method call a private helper like $this->e()?The included code runs in the method's call frame, with the same `$this` and the same class scope. Visibility is checked against that scope, so private and protected members of the class are accessible, exactly as if the template's code were written inside the method body.
saying these in an interview costs you the question
- Included files always run in the global scope
- An included file gets its own private variable scope like a function
- Functions declared in a file included inside a function are local to it
- The included file inherits the includer's namespace and use imports
- __DIR__ inside an included file points to the including script's directory