0
0
PHPprogramming~15 mins

Declare strict_types directive in PHP - Deep Dive

Choose your learning style9 modes available
Overview - Declare strict_types directive
What is it?
The declare strict_types directive in PHP is a special instruction placed at the top of a PHP file that tells the interpreter to enforce strict type checking for function calls and return values. When enabled, PHP will not automatically convert types for function arguments or return values, requiring exact matches. This helps catch type errors early and makes code behavior more predictable.
Why it matters
Without strict_types, PHP automatically converts types in many situations, which can hide bugs and cause unexpected behavior. Strict typing forces developers to be explicit about data types, improving code quality and reducing runtime errors. This is especially important in large projects or when working with APIs where type safety matters.
Where it fits
Before learning strict_types, you should understand PHP's basic type system and how functions work. After mastering strict_types, you can explore advanced type declarations, type hinting, and PHP 8's union and mixed types for even stronger type safety.
Mental Model
Core Idea
Declare strict_types tells PHP to stop guessing and require exact data types for function inputs and outputs.
Think of it like...
It's like setting a rule in a kitchen that only exact ingredients can be used in a recipe, no substitutions allowed, so the dish always turns out as expected.
┌─────────────────────────────┐
│ PHP File with declare(strict_types=1); │
├─────────────────────────────┤
│ Function expects int         │
│ Caller passes '5' (string)  │
│ ─────────────────────────── │
│ Without strict_types: PHP converts '5' to 5 (int) silently
│ With strict_types: PHP throws a TypeError
└─────────────────────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding PHP's default type behavior
🤔
Concept: PHP automatically converts types when calling functions unless strict_types is declared.
In PHP, if a function expects an integer but you pass a string like '5', PHP will convert it to an integer automatically. For example: function addOne(int $num) { return $num + 1; } echo addOne('5'); // outputs 6 Here, PHP converts the string '5' to integer 5 without error.
Result
The function runs successfully and outputs 6, even though the input was a string.
Understanding PHP's default behavior helps you see why silent type conversions can hide bugs.
2
FoundationWhat declare(strict_types=1) does
🤔
Concept: The declare(strict_types=1) directive enforces exact type matching for function calls and returns.
At the very top of a PHP file, you can write: declare(strict_types=1); This tells PHP to stop automatic type conversion for that file. Now, if a function expects an int and you pass a string, PHP will throw a TypeError instead of converting it.
Result
Passing '5' (string) to a function expecting int causes a TypeError.
Knowing this directive exists lets you control how strict PHP is about types, improving code safety.
3
IntermediatePlacement and scope of strict_types directive
🤔
Concept: strict_types applies per file and must be declared at the top before any code.
The declare(strict_types=1); line must be the very first statement in a PHP file, before any whitespace or code. It affects only that file's function calls and return values. If you include or require other files without strict_types, those files use PHP's default behavior. Example: // file1.php
Result
strict_types controls type checking only in the file where it is declared.
Understanding scope prevents confusion about why some files enforce strict types and others don't.
4
IntermediateEffect on return types and function arguments
🤔
Concept: strict_types enforces exact types on both function arguments and return values.
With strict_types enabled, PHP checks: - That arguments passed to functions exactly match declared types. - That functions return values exactly matching their declared return types. Example: declare(strict_types=1); function getNumber(): int { return '5'; // TypeError because return is string, not int } getNumber(); This throws an error because the return type is string, not int.
Result
TypeErrors occur if return types do not match exactly under strict_types.
Knowing strict_types affects both inputs and outputs helps write fully type-safe functions.
5
IntermediateInterplay with type declarations and coercion
🤔Before reading on: Do you think strict_types affects type coercion inside function bodies or only at call boundaries? Commit to your answer.
Concept: strict_types only affects type checking at function call and return boundaries, not inside function bodies.
Inside a function, PHP still allows normal operations and conversions. strict_types does not change how PHP handles types internally, only how it checks types when calling or returning. Example: declare(strict_types=1); function add(int $a, int $b): int { return $a + $b; // addition works normally } add(2, 3); // works fine But add('2', 3); // TypeError because argument '2' is string Inside the function, $a and $b are guaranteed ints, so operations are safe.
Result
strict_types enforces type safety at boundaries but does not restrict internal operations.
Understanding this boundary focus clarifies where strict_types applies and where PHP remains flexible.
6
AdvancedCommon pitfalls with strict_types and mixed files
🤔Before reading on: If you call a strict_types file function from a non-strict file, do you think strict_types applies? Commit to your answer.
Concept: strict_types applies only to the caller file, not the callee file, which can cause unexpected behavior when mixing strict and non-strict files.
If a file with strict_types calls a function defined in a non-strict file, the call is checked strictly. But if a non-strict file calls a function in a strict_types file, the call is not checked strictly. Example: // strict.php
Result
strict_types enforcement depends on the caller file, not the function definition file.
Knowing this caller-based enforcement prevents subtle bugs in mixed codebases.
7
ExpertWhy strict_types is a directive, not a global setting
🤔Before reading on: Why do you think PHP made strict_types a per-file directive instead of a global setting? Commit to your answer.
Concept: strict_types is per-file to maintain backward compatibility and allow gradual adoption in large projects.
PHP was originally loosely typed, so changing to strict typing globally would break existing code. By making strict_types a per-file directive, developers can enable strict typing gradually, file by file. This design balances safety with flexibility, letting projects migrate at their own pace. However, this also means developers must be careful about mixing strict and non-strict files.
Result
strict_types as a directive allows gradual adoption but requires awareness of scope.
Understanding the design tradeoff explains why strict_types behaves the way it does and guides best practices.
Under the Hood
When PHP parses a file with declare(strict_types=1), it sets an internal flag for that file's execution context. During function calls and returns, PHP checks this flag in the caller's context to decide whether to enforce strict type checks. If strict_types is enabled, PHP compares the actual argument types exactly to the declared types and throws TypeErrors on mismatch. Otherwise, PHP performs type coercion silently. This flag does not affect code inside the function body, only the call and return boundaries.
Why designed this way?
PHP was designed as a loosely typed language for ease of use and rapid development. Introducing strict typing globally would break millions of existing scripts. The per-file declare(strict_types=1) directive was introduced in PHP 7 to allow developers to opt-in to strict typing gradually. This design preserves backward compatibility while enabling safer, more predictable code where desired.
┌─────────────────────────────┐
│ PHP File Execution Context   │
│ ┌─────────────────────────┐ │
│ │ strict_types flag = 1   │ │
│ └─────────────────────────┘ │
│                             │
│ Caller function call         │
│ ┌─────────────────────────┐ │
│ │ Check strict_types flag  │─┼─> If 1, enforce exact types
│ └─────────────────────────┘ │
│                             │
│ Function execution (body)    │
│ ┌─────────────────────────┐ │
│ │ No strict enforcement    │ │
│ └─────────────────────────┘ │
│                             │
│ Return from function        │
│ ┌─────────────────────────┐ │
│ │ Check strict_types flag  │─┼─> If 1, enforce exact return type
│ └─────────────────────────┘ │
└─────────────────────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does declare(strict_types=1) affect all files in a project automatically? Commit to yes or no.
Common Belief:Many believe that declaring strict_types in one file makes the whole project strict.
Tap to reveal reality
Reality:strict_types applies only to the file where it is declared, affecting calls made from that file only.
Why it matters:Assuming global effect leads to unexpected type errors or silent bugs when mixing strict and non-strict files.
Quick: Does strict_types prevent all type coercion in PHP? Commit to yes or no.
Common Belief:Some think strict_types disables all type conversions everywhere in PHP.
Tap to reveal reality
Reality:strict_types only enforces type checks at function call and return boundaries, not inside function bodies or other operations.
Why it matters:Expecting full strictness can cause confusion about why some type coercions still happen.
Quick: If a function is defined in a strict_types file, is it always called with strict checking? Commit to yes or no.
Common Belief:People often believe that functions defined in strict_types files always enforce strict typing regardless of caller.
Tap to reveal reality
Reality:strict_types enforcement depends on the caller file, not the function definition file.
Why it matters:This misconception can cause bugs when calling strict functions from non-strict files without errors.
Quick: Does declare(strict_types=1) affect type declarations like class properties? Commit to yes or no.
Common Belief:Some think strict_types affects all type declarations including class properties and internal operations.
Tap to reveal reality
Reality:strict_types only affects function calls and returns, not property type declarations or internal PHP behavior.
Why it matters:Misunderstanding this leads to incorrect assumptions about type safety in object properties.
Expert Zone
1
strict_types enforcement is determined by the caller's file context, which can cause subtle bugs in mixed strict and non-strict codebases.
2
The directive must be the very first statement in a file, immediately after the opening
3
strict_types does not affect internal PHP functions or extensions, only user-defined functions in PHP code.
When NOT to use
Avoid using strict_types in legacy projects with many loosely typed functions unless you can refactor all related code. Instead, use gradual typing tools or static analyzers like PHPStan or Psalm to improve type safety without runtime strictness.
Production Patterns
In production, strict_types is often enabled on new modules or APIs to ensure type safety, while legacy code remains non-strict. Developers use strict_types combined with typed properties and union types to build robust, maintainable systems. Continuous integration pipelines run static analysis to catch type issues before runtime.
Connections
Static Type Checking
strict_types complements static type checking by enforcing types at runtime, while static analysis checks types before running code.
Understanding strict_types helps appreciate the balance between compile-time and runtime type safety.
Type Systems in Programming Languages
strict_types is PHP's way to add optional strong typing, similar to how languages like TypeScript add types to JavaScript.
Knowing strict_types connects PHP's dynamic typing with broader type system concepts across languages.
Quality Control in Manufacturing
strict_types acts like a quality control checkpoint ensuring only exact parts (types) fit into a machine (function), preventing defects.
This cross-domain link shows how enforcing exact matches prevents errors both in code and physical production.
Common Pitfalls
#1Expecting strict_types to apply globally across all files.
Wrong approach:
Correct approach:
Root cause:Misunderstanding that strict_types applies per file, not globally.
#2Placing declare(strict_types=1) after code or whitespace.
Wrong approach:
Correct approach:
Root cause:Not knowing strict_types must be the very first statement in the file.
#3Assuming strict_types affects internal PHP functions.
Wrong approach:
Correct approach:Use explicit casts or wrapper functions to ensure correct types when calling internal functions.
Root cause:Believing strict_types enforces types on all PHP functions, including built-ins.
Key Takeaways
The declare(strict_types=1) directive enforces exact type matching for function calls and returns in the file where it is declared.
strict_types applies only at the boundaries of function calls and returns, not inside function bodies or on class properties.
The directive must be the very first statement in a PHP file to take effect.
strict_types enforcement depends on the caller file, which can cause subtle bugs when mixing strict and non-strict files.
Using strict_types improves code safety and predictability but requires careful adoption in existing projects.