PHP Magic Constants

sa sahaya jerish Updated 17 Oct 2026
9 min read ·Lesson 75 of 109
In this post

What Are Magic Constants? In simple terms: Magic constants are special names, written with double underscores, that tell you where a piece of code is: which file, which folder, which line, which funct

What Are Magic Constants?

In simple terms: Magic constants are special names, written with double underscores, that tell you where a piece of code is: which file, which folder, which line, which function, or which class.

Technically: Magic constants look like constants but their value depends on the location in the source code where they are written. PHP replaces them with the correct value when it compiles the file. They are predefined by PHP, cannot be redefined, and (unlike normal constants) are case-insensitive — although they are always written in uppercase by convention.

Why They Exist

Code often needs information about itself:

  • File paths: to include other files reliably, regardless of where the script was started from.
  • Debugging and logging: to record which file, line, or method produced a message.
  • Class names as strings: for factories, dependency injection, routing, and error messages, without typing names by hand.

Magic constants provide this information automatically, so it never gets out of date when files or classes are renamed or moved.


Overview

Magic ConstantValue
__LINE__The current line number in the file
__FILE__The full path and file name of the current file (symlinks resolved)
__DIR__The directory of the current file (same as dirname(__FILE__))
__FUNCTION__The name of the current function or method
__CLASS__The fully qualified name of the current class
__METHOD__The class and method name, e.g. App\Order::save
__NAMESPACE__The current namespace (empty in the global namespace)
__TRAIT__The fully qualified name of the current trait
__PROPERTY__The name of the current property inside a property hook (PHP 8.4+)
ClassName::classThe fully qualified class name as a string (not technically a magic constant, but resolved the same way)

__LINE__, __FILE__, and __DIR__

Example

Assume this code is saved as /var/www/shop/public/info.php:

<?php
echo "Line: " . __LINE__ . "\n";
echo "File: " . __FILE__ . "\n";
echo "Directory: " . __DIR__ . "\n";
echo "File name only: " . basename(__FILE__) . "\n";
echo "Parent directory: " . dirname(__DIR__) . "\n";

Output

Line: 2
File: /var/www/shop/public/info.php
Directory: /var/www/shop/public
File name only: info.php
Parent directory: /var/www/shop

How It Works

  • __LINE__ is replaced with the line number on which it appears (line 2 here).
  • __FILE__ is the absolute path of the file containing the code, even if that file was included by another file.
  • __DIR__ is the directory of that file, without a trailing slash (except for the root directory /).
  • basename() returns the last part of a path; dirname() returns the parent directory. dirname(__DIR__, 2) goes up two levels.

On Windows, paths look like C:\xampp\htdocs\shop\public\info.php.


Reliable Includes With __DIR__

The Problem With Relative Paths

<?php
// public/index.php
require 'config/app.php';

A relative path such as 'config/app.php' is resolved against PHP's include_path and the current working directory — the directory from which PHP was started — not against the location of index.php. The same file may work in the browser but fail when run from a cron job, a test runner, or another directory.

The Solution

shop/
├── config/
│   └── app.php
├── src/
│   └── helpers.php
└── public/
    └── index.php
<?php
// public/index.php
$projectRoot = dirname(__DIR__);

require $projectRoot . '/config/app.php';
require $projectRoot . '/src/helpers.php';

Why This Works

  • __DIR__ is always the directory of index.php itself: .../shop/public.
  • dirname(__DIR__) is the project root: .../shop.
  • The final paths are absolute, so they work no matter where PHP was started from.

This is the standard way to include files in modern PHP code. Composer's autoloader is included the same way: require dirname(__DIR__) . '/vendor/autoload.php';.

Security note: Never build include paths from user input (require $_GET['page'] . '.php'). That allows attackers to include unexpected files. Map allowed page names to known file paths instead. See PHP Include.


__FUNCTION__, __CLASS__, __METHOD__, __NAMESPACE__, and __TRAIT__

Example

Assume this file is /var/www/shop/src/Reports/SalesReport.php:

<?php
// File: /var/www/shop/src/Reports/SalesReport.php
namespace App\Reports;

trait Loggable
{
    public function logContext(): string
    {
        return __TRAIT__ . ' used in ' . __CLASS__;
    }
}

class SalesReport
{
    use Loggable;

    public function build(): void
    {
        echo "Namespace: " . __NAMESPACE__ . "\n";
        echo "Class:     " . __CLASS__ . "\n";
        echo "Method:    " . __METHOD__ . "\n";
        echo "Function:  " . __FUNCTION__ . "\n";
        echo "Line:      " . __LINE__ . "\n";
        echo "Context:   " . $this->logContext() . "\n";
    }
}

(new SalesReport())->build();
echo "Class name: " . SalesReport::class . "\n";

Output

Namespace: App\Reports
Class:     App\Reports\SalesReport
Method:    App\Reports\SalesReport::build
Function:  build
Line:      23
Context:   App\Reports\Loggable used in App\Reports\SalesReport
Class name: App\Reports\SalesReport

What Each Constant Shows

ConstantResultExplanation
__NAMESPACE__App\ReportsThe namespace declared at the top of the file
__CLASS__App\Reports\SalesReportThe fully qualified class name, including the namespace
__METHOD__App\Reports\SalesReport::buildClass and method combined — useful in log messages
__FUNCTION__buildOnly the method name
__TRAIT__App\Reports\LoggableThe trait in which the code is written
__CLASS__ inside a traitApp\Reports\SalesReportThe class that uses the trait, not the trait itself

Namespaces, classes, and traits are covered in the PHP OOP section. The important point here: these values are always correct and update automatically if you rename the class or move it to another namespace.

Outside Classes and Functions

<?php
function calculateShipping(): string
{
    return __FUNCTION__;
}

echo calculateShipping() . "\n";
var_dump(__CLASS__);
var_dump(__NAMESPACE__);

Output

calculateShipping
string(0) ""
string(0) ""

Outside a class, __CLASS__ is an empty string; in the global namespace, __NAMESPACE__ is empty too.


ClassName::class

::class returns the fully qualified name of a class as a string, resolved at compile time using the current namespace and use imports.

Example

<?php
namespace App\Billing;

use App\Reports\SalesReport;

class Invoice {}

echo Invoice::class . "\n";
echo SalesReport::class . "\n";

$invoice = new Invoice();
echo $invoice::class . "\n";

Output

App\Billing\Invoice
App\Reports\SalesReport
App\Billing\Invoice

Why Use ::class Instead of Writing the Name

  • No typos. A misspelled string such as 'App\Biling\Invoice' fails only at runtime; a misspelled class in Invoce::class is flagged by editors and static analysis tools.
  • Refactoring. IDEs rename Invoice::class automatically when the class is renamed.
  • Imports. SalesReport::class resolves through the use statement, so you do not repeat the full namespace.

::class on a class name does not require the class to exist or be loaded — it only resolves the name. Using ::class on an object ($invoice::class) is available since PHP 8.0 and is equivalent to get_class($invoice).

Common uses include registering classes in dependency injection containers, mapping routes to controllers, and writing log messages.


__PROPERTY__ (PHP 8.4+)

PHP 8.4 introduced property hooks, which run code when a property is read or written. Inside a hook, __PROPERTY__ contains the property's name.

Example

<?php
class Product
{
    public string $name {
        set(string $value) {
            $value = trim($value);

            if ($value === '') {
                throw new InvalidArgumentException(__PROPERTY__ . ' cannot be empty.');
            }

            $this->name = $value;
        }
    }
}

$product = new Product();
$product->name = '  Desk Lamp  ';
echo $product->name . "\n";

try {
    $product->name = '   ';
} catch (InvalidArgumentException $e) {
    echo $e->getMessage() . "\n";
}

Output

Desk Lamp
name cannot be empty.

The set hook trims and validates every assignment. Using __PROPERTY__ in the message means the same validation code can be copied to other properties without editing the property name. Property hooks are covered in Property Hooks (PHP 8.4).


Compile-Time Resolution: A Logging Pitfall

Magic constants are replaced where they are written, not where code is called. This matters for logging helpers.

Problem

<?php
// File: orders.php
function logMessage(string $message): void
{
    printf("[%s:%d] %s\n", basename(__FILE__), __LINE__, $message);
}

logMessage('Order created');
logMessage('Payment received');

Output

[orders.php:5] Order created
[orders.php:5] Payment received

Both messages report line 5 — the line inside the helper — instead of the lines where logMessage() was called. The log is useless for finding where events happened.

Solution 1: Pass the Location Explicitly

<?php
// File: orders.php
function logHere(string $message, string $file, int $line): void
{
    printf("[%s:%d] %s\n", basename($file), $line, $message);
}

logHere('Order created', __FILE__, __LINE__);

Output

[orders.php:8] Order created

The caller passes its own __FILE__ and __LINE__, which are resolved at the call site.

Solution 2: Read the Caller With debug_backtrace()

<?php
// File: orders.php
function logCaller(string $message): void
{
    $caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0];

    printf("[%s:%d] %s\n", basename($caller['file']), $caller['line'], $message);
}

logCaller('Payment received');

Output

[orders.php:10] Payment received

How It Works

  • debug_backtrace() returns information about the current call stack at runtime.
  • Element [0] describes the call to logCaller() itself; its file and line are the location of that call.
  • DEBUG_BACKTRACE_IGNORE_ARGS skips collecting function arguments, and the limit 1 returns only one frame, which keeps the call cheap.

Logging libraries such as Monolog (used by Laravel and Symfony) handle this automatically, but understanding the difference between compile-time and runtime information explains why.


Practical Example: Consistent Error Messages

<?php
namespace App\Payments;

class PaymentGateway
{
    public function charge(int $amountPaise, string $currency): string
    {
        if ($amountPaise <= 0) {
            throw new \InvalidArgumentException(
                sprintf('%s(): amount must be positive, %d given.', __METHOD__, $amountPaise)
            );
        }

        if ($currency !== 'INR') {
            throw new \InvalidArgumentException(
                sprintf('%s(): unsupported currency "%s".', __METHOD__, $currency)
            );
        }

        return 'Charged ₹' . number_format($amountPaise / 100, 2);
    }
}

$gateway = new PaymentGateway();

foreach ([[49900, 'INR'], [0, 'INR'], [1000, 'USD']] as [$amount, $currency]) {
    try {
        echo $gateway->charge($amount, $currency) . "\n";
    } catch (\InvalidArgumentException $e) {
        echo 'Error: ' . $e->getMessage() . "\n";
    }
}

Output

Charged ₹499.00
Error: App\Payments\PaymentGateway::charge(): amount must be positive, 0 given.
Error: App\Payments\PaymentGateway::charge(): unsupported currency "USD".

Step-by-Step Explanation

  1. __METHOD__ inserts App\Payments\PaymentGateway::charge into each error message, so anyone reading logs immediately knows which method rejected the input.
  2. If the class is renamed or moved to another namespace, the messages update automatically.
  3. The backslash in \InvalidArgumentException refers to the built-in class in the global namespace, because the file declares its own namespace (App\Payments). Namespaces are covered in PHP Namespaces.
  4. The loop uses array destructuring ([$amount, $currency]) to test three cases: a valid charge and two invalid inputs.

Common Mistakes

Using Relative Paths for Includes

Effect: Files are not found when the script runs from a different directory (cron jobs, CLI tools, tests).

Fix: Build paths from __DIR__.

Expecting __LINE__ or __FILE__ in a Helper to Show the Caller

Effect: Logs always point to the helper.

Fix: Pass __FILE__ and __LINE__ from the caller, or use debug_backtrace().

Confusing __CLASS__ and __TRAIT__ Inside Traits

Effect: Expecting the trait name from __CLASS__.

Fix: Use __TRAIT__ for the trait's name and __CLASS__ for the class using it.

Hard-Coding Class Names as Strings

Effect: Typos and outdated names after refactoring.

Fix: Use ClassName::class.

Exposing Paths to Users

Effect: Error pages showing __FILE__ or __DIR__ reveal the server's directory structure.

Fix: Write such details to logs, not to responses (see Error Reporting in Production).


Best Practices

  • Use __DIR__ (and dirname(__DIR__)) for every require and include path.
  • Use ClassName::class whenever a class name is needed as a string.
  • Use __METHOD__ in exception messages and log entries to identify their source.
  • Remember that magic constants are resolved where they are written; use runtime tools for caller information.
  • Write magic constants in uppercase for readability, even though PHP accepts any case.

Official reference: https://www.php.net/manual/en/language.constants.magic.php

0 Comments

Reviewed before they appear

No comments yet.

PHP
PHP Home PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement PHP Home PHP Intro PHP Install PHP Built-in Web Server PHP Syntax PHP Tags PHP and HTML PHP Comments PHP Multiline Comments PHP Variables Variables Scope PHP Casting Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence Continue Statement Modify Strings PHP If...Else...Elseif PHP If Modify Strings PHP If Operators PHP Functions Concatenate Strings PHP If...Else Slicing Strings User-defined Functions Slicing Strings PHP Shorthand if Escape Characters Default Argument Values PHP Nested if Pass by Reference String Interpolation Named Arguments PHP File Upload Variadic Functions Return Values Search in Strings Multibyte Strings Type Declarations in Functions PHP Numbers PHP Math PHP Floats PHP Random Numbers PHP Constants PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Cookies PHP Destructor PHP Access Modifiers Readonly Properties PHP Sessions PHP Inheritance Method Overriding PHP Filters The final Keyword CSRF Protection PHP Filters Advanced Session Security Secure Cookies PHP Magic Constants File Upload Security PHP Callback Functions PHP Operators Filesystem Security PHP JSON Arithmetic Operators Error Reporting in Production Hiding PHP Assignment Operators PHP Configuration (php.ini) Comparison Operators PHP Command Line (CLI) PHP Exceptions Increment / Decrement Operators Migrating to PHP 8 PHP Form Validation PHP Form Required PHP Form URL/E-mail Error Handling Form Input Sanitizing Escaping Output (htmlspecialchars) Custom Error Handler Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting Error Logging HTTP Headers and Redirects Output Buffering Sending Email PHP cURL Consuming REST APIs PHP Generators
Ask about this post
AI Ask about this post

Ask questions about PHP Magic Constants and get answers drawn from it.

Signed-in readers only.