PHP Magic Constants

Ma Mahalakshmi V Updated 14 Nov 2026
9 min read ·Lesson 36 of 256

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 Tutorial Index 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 Static Variables Variable Variables PHP Echo / Print PHP printf / sprintf PHP Data Types PHP Booleans PHP NULL PHP Strings String Functions Modify Strings Concatenate Strings Slicing Strings Escape Characters String Interpolation Heredoc and Nowdoc Search in Strings Multibyte Strings PHP Floats PHP Casting PHP Type Juggling PHP Math PHP Random Numbers PHP Constants PHP Magic Constants PHP Operators Arithmetic Operators Assignment Operators Comparison Operators Increment / Decrement Operators Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence PHP If...Else...Elseif PHP If PHP If Operators PHP If...Else PHP Shorthand if PHP Nested if PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement Continue Statement PHP Functions User-defined Functions Function Arguments Default Argument Values Pass by Reference Named Arguments Variadic Functions Return Values Type Declarations in Functions Recursive Functions Variable Functions Anonymous Functions Closures Arrow Functions First-class Callable Syntax PHP Arrays Indexed Arrays Associative Arrays Create Arrays Access Array Items Update Array Items Add Array Items Remove Array Items Sorting Arrays Multidimensional Arrays Array Destructuring Array Spread Operator Search in Arrays Merge Arrays array_map / array_filter / array_reduce Array Functions PHP Superglobals $GLOBALS $_SERVER $_REQUEST $_POST $_GET $_FILES $_COOKIE $_SESSION \$\_ENV PHP RegEx RegEx Patterns RegEx Modifiers preg_match preg_replace preg_split PHP RegEx Functions PHP Form Handling PHP Form Validation PHP Form Required PHP Form URL/E-mail Form Input Sanitizing Escaping Output (htmlspecialchars) Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting DateTime Class Timezones PHP Include Include vs Require PHP File Handling PHP File Open/Read PHP File Create/Write File Delete / Rename / Copy PHP Directories PHP CSV Files PHP File Upload PHP Cookies PHP Sessions PHP Filters PHP Filters Advanced PHP Callback Functions PHP JSON PHP Exceptions Error Handling Custom Error Handler Error Logging HTTP Headers and Redirects Output Buffering Sending Email PHP cURL Consuming REST APIs PHP Generators PHP What is OOP PHP Classes/Objects The $this Keyword PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Destructor PHP Access Modifiers Readonly Properties PHP Inheritance Method Overriding The final Keyword PHP Class Constants PHP Abstract Classes PHP Interfaces Polymorphism PHP Traits PHP Static Methods PHP Static Properties Late Static Binding Magic Methods Object Cloning Comparing Objects Anonymous Classes PHP Enums PHP Namespaces Autoloading Classes PHP Iterables Iterators Object Serialization Strict Types Union Types Nullable Types Mixed and Never Types Nullsafe Operator PHP Attributes PHP Fibers Readonly Classes Property Hooks (PHP 8.4) Asymmetric Visibility (PHP 8.4) Reflection API SPL Data Structures MySQL Database MySQL Connect MySQL Create DB MySQL Create Table MySQL Insert Data MySQL Get Last ID MySQL Insert Multiple MySQL Prepared MySQL Select Data MySQL Where MySQL Order By MySQL Delete Data MySQL Update Data MySQL Limit Data MySQL Joins with PHP Pagination with PHP PDO Introduction PDO Connect PDO Prepared Statements PDO Fetch Modes PDO Transactions PDO Error Handling PHP XML Parsers PHP SimpleXML Parser PHP SimpleXML - Get PHP XML Expat Parser PHP DOM Parser PHP XMLReader PHP XMLWriter AJAX Intro AJAX PHP AJAX Database AJAX XML AJAX Live Search AJAX Poll AJAX with JSON Security Introduction Password Hashing SQL Injection Prevention XSS Prevention CSRF Protection Session Security Secure Cookies File Upload Security Filesystem Security Error Reporting in Production Hiding PHP Encryption with Sodium PHP Configuration (php.ini) PHP Command Line (CLI) Composer PSR-4 Autoloading Installing Extensions (PECL / PIE) Debugging PHP OPcache & Performance Garbage Collection PHP-FPM Migrating to PHP 8 Project: Contact Form with Email Project: Login & Registration System Project: CRUD App with MySQL Project: Image Upload Gallery Project: Shopping Cart with Sessions Project: Simple Blog Project: REST API with PHP
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.