PHP Magic Constants for Maintainable Logging Systems

PHP magic constants provide automatic context about code execution location, enabling logging systems that track method calls, file locations, and class hierarchies without manual instrumentation. Combined with Monolog and PSR-3 logging standards, these constants create maintainable logging architectures that scale with application complexity.

Understanding PHP Magic Constants

PHP provides eight magic constants that automatically resolve to contextual values at compile time. Unlike regular constants, these values change based on their location in the code, making them invaluable for debugging and logging systems.

Complete Magic Constants Reference

Each magic constant serves specific debugging and logging purposes:

<?php

// Basic demonstration of all PHP magic constants
class ExampleService
{
    public function demonstrateMagicConstants(): array
    {
        return [
            '__FILE__' => __FILE__,
            '__DIR__' => __DIR__,
            '__LINE__' => __LINE__,
            '__FUNCTION__' => __FUNCTION__,
            '__CLASS__' => __CLASS__,
            '__METHOD__' => __METHOD__,
            '__NAMESPACE__' => __NAMESPACE__,
            '__TRAIT__' => null, // Only available inside traits
        ];
    }
}

trait ExampleTrait
{
    public function getTraitInfo(): string
    {
        return __TRAIT__; // Returns the trait name
    }
}

namespace App\Services {
    class NamespaceExample
    {
        public function getNamespace(): string
        {
            return __NAMESPACE__; // Returns 'App\Services'
        }
    }
}

// Usage examples
$service = new ExampleService();
$constants = $service->demonstrateMagicConstants();

foreach ($constants as $constant => $value) {
    if ($value !== null) {
        echo "{$constant}: {$value}" . PHP_EOL;
    }
}
Constant Returns Primary Use Case
__FILE__ Full file path File-based error tracking
__DIR__ Directory path Configuration and asset loading
__LINE__ Current line number Precise error location
__FUNCTION__ Function name Function-level logging
__CLASS__ Class name Class-based log categorization
__METHOD__ Class::method Method execution tracking
__NAMESPACE__ Current namespace Module-based logging
__TRAIT__ Trait name Trait-specific debugging

Monolog and PSR-3 Foundation

Monolog 3.x provides the de facto logging implementation for PHP applications, fully implementing the PSR-3 Logger Interface. The latest version requires PHP 8.1+ and offers enhanced performance and type safety.

Modern Installation and Setup

Install Monolog 3.x with proper version constraints using Composer:

{
    "name": "lts/php-magic-constants-logging",
    "description": "PHP Magic Constants for Maintainable Logging Systems",
    "type": "project",
    "require": {
        "php": "^8.1",
        "monolog/monolog": "^3.0",
        "psr/log": "^3.0"
    },
    "require-dev": {
        "phpunit/phpunit": "^10.0",
        "phpstan/phpstan": "^1.10",
        "friendsofphp/php-cs-fixer": "^3.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "App\\Tests\\": "tests/"
        }
    },
    "config": {
        "optimize-autoloader": true,
        "preferred-install": "dist",
        "sort-packages": true
    },
    "minimum-stability": "stable",
    "prefer-stable": true
}

The enhanced logger demonstrates magic constants integration with Monolog's processor system:

<?php

declare(strict_types=1);

namespace App\Logging;

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Processor\IntrospectionProcessor;
use Monolog\Processor\PsrLogMessageProcessor;
use Monolog\Formatter\JsonFormatter;
use Psr\Log\LoggerInterface;

/**
 * Enhanced logger that leverages PHP magic constants for contextual logging
 */
class EnhancedLogger
{
    private LoggerInterface $logger;
    
    public function __construct(string $channel = 'app')
    {
        $this->logger = new Logger($channel);
        
        // Add handlers for different log levels
        $this->setupHandlers();
        
        // Add processors for enhanced context
        $this->setupProcessors();
    }
    
    private function setupHandlers(): void
    {
        // Daily rotating logs with JSON formatting
        $rotatingHandler = new RotatingFileHandler(
            __DIR__ . '/../../var/logs/app.log',
            7, // Keep 7 days
            Logger::DEBUG
        );
        $rotatingHandler->setFormatter(new JsonFormatter());
        
        // Error-specific handler
        $errorHandler = new StreamHandler(
            __DIR__ . '/../../var/logs/errors.log',
            Logger::ERROR
        );
        $errorHandler->setFormatter(new JsonFormatter());
        
        $this->logger->pushHandler($rotatingHandler);
        $this->logger->pushHandler($errorHandler);
    }
    
    private function setupProcessors(): void
    {
        // PSR-3 message processing for placeholder interpolation
        $this->logger->pushProcessor(new PsrLogMessageProcessor());
        
        // Introspection processor adds file, line, class, function info
        $this->logger->pushProcessor(new IntrospectionProcessor());
    }
    
    /**
     * Create context-aware log entry using magic constants
     */
    public function logWithContext(
        string $level,
        string $message,
        array $context = [],
        ?string $callerFile = null,
        ?int $callerLine = null,
        ?string $callerFunction = null,
        ?string $callerClass = null,
        ?string $callerMethod = null
    ): void {
        // Enhance context with caller information
        $enhancedContext = array_merge($context, [
            'caller' => [
                'file' => $callerFile ?? 'unknown',
                'line' => $callerLine ?? 0,
                'function' => $callerFunction ?? 'unknown',
                'class' => $callerClass ?? 'unknown',
                'method' => $callerMethod ?? 'unknown',
            ],
            'timestamp' => date('c'),
        ]);
        
        $this->logger->log($level, $message, $enhancedContext);
    }
    
    /**
     * Helper method to create a context-aware info log
     */
    public function info(string $message, array $context = []): void
    {
        $this->logWithContext(
            'info',
            $message,
            $context,
            debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'] ?? null,
            debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['line'] ?? null,
            debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['function'] ?? null,
            debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['class'] ?? null
        );
    }
    
    /**
     * Get the underlying logger instance
     */
    public function getLogger(): LoggerInterface
    {
        return $this->logger;
    }
}

Automatic Context with Logging Traits

Traits provide reusable logging functionality that automatically injects magic constants into log context. This approach eliminates manual context building while maintaining consistency across application components.

<?php

declare(strict_types=1);

namespace App\Logging;

use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;

/**
 * Logging trait that automatically includes magic constants in log context
 */
trait LoggingTrait
{
    private LoggerInterface $logger;
    
    /**
     * Set the logger instance
     */
    public function setLogger(LoggerInterface $logger): void
    {
        $this->logger = $logger;
    }
    
    /**
     * Log with automatic context enrichment using magic constants
     */
    protected function log(
        string $level,
        string $message,
        array $context = []
    ): void {
        if (!isset($this->logger)) {
            return; // Graceful degradation if no logger set
        }
        
        // Enrich context with magic constants and caller information
        $enrichedContext = array_merge($context, [
            'source' => [
                'file' => __FILE__,
                'line' => __LINE__,
                'class' => __CLASS__,
                'trait' => __TRAIT__,
                'method' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['function'] ?? 'unknown',
            ],
            'runtime' => [
                'memory_usage' => memory_get_usage(true),
                'peak_memory' => memory_get_peak_usage(true),
                'execution_time' => microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'],
            ]
        ]);
        
        $this->logger->log($level, $message, $enrichedContext);
    }
    
    /**
     * Log debug information
     */
    protected function logDebug(string $message, array $context = []): void
    {
        $this->log(LogLevel::DEBUG, $message, $context);
    }
    
    /**
     * Log informational messages
     */
    protected function logInfo(string $message, array $context = []): void
    {
        $this->log(LogLevel::INFO, $message, $context);
    }
    
    /**
     * Log warning messages
     */
    protected function logWarning(string $message, array $context = []): void
    {
        $this->log(LogLevel::WARNING, $message, $context);
    }
    
    /**
     * Log error messages
     */
    protected function logError(string $message, array $context = []): void
    {
        $this->log(LogLevel::ERROR, $message, $context);
    }
    
    /**
     * Log critical errors
     */
    protected function logCritical(string $message, array $context = []): void
    {
        $this->log(LogLevel::CRITICAL, $message, $context);
    }
    
    /**
     * Log method entry with parameters
     */
    protected function logMethodEntry(array $parameters = []): void
    {
        $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
        $caller = $backtrace[1] ?? [];
        
        $this->logDebug('Method entry', [
            'method' => ($caller['class'] ?? '') . '::' . ($caller['function'] ?? 'unknown'),
            'parameters' => $parameters,
            'source_line' => $backtrace[0]['line'] ?? 0,
        ]);
    }
    
    /**
     * Log method exit with return value
     */
    protected function logMethodExit($returnValue = null): void
    {
        $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
        $caller = $backtrace[1] ?? [];
        
        $this->logDebug('Method exit', [
            'method' => ($caller['class'] ?? '') . '::' . ($caller['function'] ?? 'unknown'),
            'return_value' => $returnValue,
            'source_line' => $backtrace[0]['line'] ?? 0,
        ]);
    }
}

Service Integration Pattern

Services using the logging trait automatically gain contextual logging without modifying business logic:

<?php

declare(strict_types=1);

namespace App\Services;

use App\Logging\LoggingTrait;
use Psr\Log\LoggerInterface;

/**
 * Example service demonstrating magic constants in logging
 */
class UserService
{
    use LoggingTrait;
    
    private array $users = [];
    
    public function __construct(LoggerInterface $logger)
    {
        $this->setLogger($logger);
        $this->logInfo('UserService initialized', [
            'initialization_file' => __FILE__,
            'initialization_line' => __LINE__,
            'class' => __CLASS__,
            'method' => __METHOD__,
        ]);
    }
    
    /**
     * Create a new user
     */
    public function createUser(array $userData): array
    {
        $this->logMethodEntry(['userData' => $userData]);
        
        try {
            $this->validateUserData($userData);
            
            $user = [
                'id' => uniqid(),
                'email' => $userData['email'],
                'name' => $userData['name'],
                'created_at' => date('c'),
                'created_from' => [
                    'file' => __FILE__,
                    'line' => __LINE__,
                    'method' => __METHOD__,
                ]
            ];
            
            $this->users[$user['id']] = $user;
            
            $this->logInfo('User created successfully', [
                'user_id' => $user['id'],
                'email' => $user['email'],
                'source_method' => __METHOD__,
                'source_line' => __LINE__,
            ]);
            
            $this->logMethodExit($user);
            return $user;
            
        } catch (\Exception $e) {
            $this->logError('Failed to create user', [
                'error_message' => $e->getMessage(),
                'error_file' => $e->getFile(),
                'error_line' => $e->getLine(),
                'input_data' => $userData,
                'method' => __METHOD__,
                'line' => __LINE__,
            ]);
            
            throw $e;
        }
    }
    
    /**
     * Retrieve user by ID
     */
    public function getUser(string $userId): ?array
    {
        $this->logDebug('Attempting to retrieve user', [
            'user_id' => $userId,
            'method' => __METHOD__,
            'line' => __LINE__,
        ]);
        
        $user = $this->users[$userId] ?? null;
        
        if ($user === null) {
            $this->logWarning('User not found', [
                'user_id' => $userId,
                'available_users' => array_keys($this->users),
                'method' => __METHOD__,
                'line' => __LINE__,
            ]);
        } else {
            $this->logInfo('User retrieved successfully', [
                'user_id' => $userId,
                'method' => __METHOD__,
                'line' => __LINE__,
            ]);
        }
        
        return $user;
    }
    
    /**
     * Private method to validate user data
     */
    private function validateUserData(array $userData): void
    {
        $this->logDebug('Validating user data', [
            'validation_keys' => array_keys($userData),
            'method' => __METHOD__,
            'line' => __LINE__,
        ]);
        
        $requiredFields = ['email', 'name'];
        $missingFields = array_diff($requiredFields, array_keys($userData));
        
        if (!empty($missingFields)) {
            $this->logError('User data validation failed', [
                'missing_fields' => $missingFields,
                'provided_fields' => array_keys($userData),
                'method' => __METHOD__,
                'line' => __LINE__,
            ]);
            
            throw new \InvalidArgumentException(
                'Missing required fields: ' . implode(', ', $missingFields)
            );
        }
        
        if (!filter_var($userData['email'], FILTER_VALIDATE_EMAIL)) {
            $this->logError('Invalid email format', [
                'email' => $userData['email'],
                'method' => __METHOD__,
                'line' => __LINE__,
            ]);
            
            throw new \InvalidArgumentException('Invalid email format');
        }
        
        $this->logDebug('User data validation passed', [
            'method' => __METHOD__,
            'line' => __LINE__,
        ]);
    }
    
    /**
     * Get all users with logging
     */
    public function getAllUsers(): array
    {
        $this->logInfo('Retrieving all users', [
            'total_users' => count($this->users),
            'method' => __METHOD__,
            'line' => __LINE__,
        ]);
        
        return array_values($this->users);
    }
}

Advanced Context Processing

Custom Monolog processors enhance log records with magic constants and runtime information. The DebugContextProcessor demonstrates sophisticated context enrichment:

<?php

declare(strict_types=1);

namespace App\Logging\Processors;

use Monolog\LogRecord;
use Monolog\Processor\ProcessorInterface;

/**
 * Custom Monolog processor that enriches log records with debugging context
 * using PHP magic constants and runtime information
 */
class DebugContextProcessor implements ProcessorInterface
{
    private bool $includeTrace;
    private int $skipStackFrames;
    
    public function __construct(bool $includeTrace = false, int $skipStackFrames = 0)
    {
        $this->includeTrace = $includeTrace;
        $this->skipStackFrames = $skipStackFrames;
    }
    
    /**
     * Process log record and add debugging context
     */
    public function __invoke(LogRecord $record): LogRecord
    {
        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10 + $this->skipStackFrames);
        
        // Find the first frame that's not from the logging system
        $relevantFrame = $this->findRelevantFrame($trace);
        
        if ($relevantFrame) {
            $extra = $record->extra;
            
            // Add magic constants context
            $extra['debug_context'] = [
                'file' => $relevantFrame['file'] ?? 'unknown',
                'line' => $relevantFrame['line'] ?? 0,
                'function' => $relevantFrame['function'] ?? 'unknown',
                'class' => $relevantFrame['class'] ?? null,
                'type' => $relevantFrame['type'] ?? null,
            ];
            
            // Add runtime context
            $extra['runtime_context'] = [
                'memory_usage' => $this->formatBytes(memory_get_usage(true)),
                'peak_memory' => $this->formatBytes(memory_get_peak_usage(true)),
                'included_files_count' => count(get_included_files()),
                'declared_classes_count' => count(get_declared_classes()),
            ];
            
            // Add environment context
            $extra['environment_context'] = [
                'php_version' => PHP_VERSION,
                'sapi_name' => PHP_SAPI,
                'os' => PHP_OS_FAMILY,
                'server_software' => $_SERVER['SERVER_SOFTWARE'] ?? 'CLI',
            ];
            
            // Optionally include stack trace
            if ($this->includeTrace) {
                $extra['stack_trace'] = $this->formatStackTrace($trace);
            }
            
            return $record->with(extra: $extra);
        }
        
        return $record;
    }
    
    /**
     * Find the most relevant frame in the stack trace
     */
    private function findRelevantFrame(array $trace): ?array
    {
        $ignoredClasses = [
            'Monolog\\',
            'Psr\\Log\\',
            'App\\Logging\\',
        ];
        
        foreach ($trace as $frame) {
            if (!isset($frame['class'])) {
                return $frame; // Function call, likely relevant
            }
            
            $isIgnored = false;
            foreach ($ignoredClasses as $ignoredClass) {
                if (strpos($frame['class'], $ignoredClass) === 0) {
                    $isIgnored = true;
                    break;
                }
            }
            
            if (!$isIgnored) {
                return $frame;
            }
        }
        
        return $trace[0] ?? null; // Fallback to first frame
    }
    
    /**
     * Format stack trace for logging
     */
    private function formatStackTrace(array $trace): array
    {
        $formatted = [];
        
        foreach ($trace as $index => $frame) {
            $formatted[] = sprintf(
                '#%d %s%s%s() called at [%s:%d]',
                $index,
                $frame['class'] ?? '',
                $frame['type'] ?? '',
                $frame['function'] ?? 'unknown',
                $frame['file'] ?? 'unknown',
                $frame['line'] ?? 0
            );
        }
        
        return $formatted;
    }
    
    /**
     * Format bytes into human-readable format
     */
    private function formatBytes(int $bytes): string
    {
        $units = ['B', 'KB', 'MB', 'GB', 'TB'];
        $power = $bytes > 0 ? floor(log($bytes, 1024)) : 0;
        
        return round($bytes / (1024 ** $power), 2) . ' ' . $units[$power];
    }
}

Processor Benefits

  • Automatic Context: Magic constants added without manual intervention
  • Stack Trace Analysis: Intelligent frame selection ignoring logging infrastructure
  • Runtime Metrics: Memory usage and performance data included
  • Environment Context: PHP version, SAPI, and system information

Performance-Aware Logging

Performance logging leverages magic constants for method timing and resource monitoring. The performance logger provides millisecond-precision timing with automatic context:

<?php

declare(strict_types=1);

namespace App\Logging;

use Psr\Log\LoggerInterface;

/**
 * Performance-focused logger that uses magic constants for method timing
 */
class PerformanceLogger
{
    private LoggerInterface $logger;
    private array $timers = [];
    private array $counters = [];
    
    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }
    
    /**
     * Start timing a method or operation
     */
    public function startTimer(
        ?string $identifier = null,
        ?string $callerMethod = null,
        ?string $callerClass = null,
        ?int $callerLine = null
    ): string {
        // Auto-generate identifier if not provided
        if ($identifier === null) {
            $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0];
            $identifier = sprintf(
                '%s::%s@%d',
                $callerClass ?? $backtrace['class'] ?? 'global',
                $callerMethod ?? $backtrace['function'] ?? 'unknown',
                $callerLine ?? $backtrace['line'] ?? 0
            );
        }
        
        $this->timers[$identifier] = [
            'start_time' => microtime(true),
            'memory_start' => memory_get_usage(true),
            'caller_method' => $callerMethod,
            'caller_class' => $callerClass,
            'caller_line' => $callerLine,
        ];
        
        $this->logger->debug('Timer started', [
            'timer_id' => $identifier,
            'method' => $callerMethod,
            'class' => $callerClass,
            'line' => $callerLine,
            'memory_at_start' => $this->formatBytes(memory_get_usage(true)),
        ]);
        
        return $identifier;
    }
    
    /**
     * Stop timing and log performance metrics
     */
    public function stopTimer(
        string $identifier,
        array $additionalContext = []
    ): array {
        if (!isset($this->timers[$identifier])) {
            $this->logger->warning('Timer not found', [
                'timer_id' => $identifier,
                'available_timers' => array_keys($this->timers),
            ]);
            return [];
        }
        
        $timer = $this->timers[$identifier];
        $endTime = microtime(true);
        $endMemory = memory_get_usage(true);
        
        $metrics = [
            'timer_id' => $identifier,
            'execution_time_ms' => round(($endTime - $timer['start_time']) * 1000, 3),
            'memory_usage_delta' => $endMemory - $timer['memory_start'],
            'memory_usage_delta_formatted' => $this->formatBytes($endMemory - $timer['memory_start']),
            'peak_memory' => $this->formatBytes(memory_get_peak_usage(true)),
            'caller_method' => $timer['caller_method'],
            'caller_class' => $timer['caller_class'],
            'caller_line' => $timer['caller_line'],
        ];
        
        $finalContext = array_merge($metrics, $additionalContext);
        
        // Log at different levels based on execution time
        $executionTime = $metrics['execution_time_ms'];
        if ($executionTime > 1000) {
            $this->logger->warning('Slow operation detected', $finalContext);
        } elseif ($executionTime > 500) {
            $this->logger->info('Operation completed (moderate duration)', $finalContext);
        } else {
            $this->logger->debug('Operation completed', $finalContext);
        }
        
        unset($this->timers[$identifier]);
        return $metrics;
    }
    
    /**
     * Increment a performance counter
     */
    public function incrementCounter(
        string $counterName,
        int $increment = 1,
        ?string $callerMethod = null,
        ?string $callerClass = null
    ): int {
        if (!isset($this->counters[$counterName])) {
            $this->counters[$counterName] = 0;
        }
        
        $this->counters[$counterName] += $increment;
        
        $this->logger->debug('Counter incremented', [
            'counter_name' => $counterName,
            'increment' => $increment,
            'new_value' => $this->counters[$counterName],
            'caller_method' => $callerMethod,
            'caller_class' => $callerClass,
        ]);
        
        return $this->counters[$counterName];
    }
    
    /**
     * Log current performance snapshot
     */
    public function logSnapshot(
        string $label,
        ?string $callerMethod = null,
        ?string $callerClass = null,
        ?int $callerLine = null
    ): void {
        $snapshot = [
            'label' => $label,
            'timestamp' => date('c'),
            'memory_usage' => $this->formatBytes(memory_get_usage(true)),
            'peak_memory' => $this->formatBytes(memory_get_peak_usage(true)),
            'active_timers' => count($this->timers),
            'counters' => $this->counters,
            'included_files' => count(get_included_files()),
            'caller_method' => $callerMethod,
            'caller_class' => $callerClass,
            'caller_line' => $callerLine,
        ];
        
        $this->logger->info('Performance snapshot', $snapshot);
    }
    
    /**
     * Get all active timers
     */
    public function getActiveTimers(): array
    {
        return array_keys($this->timers);
    }
    
    /**
     * Get counter values
     */
    public function getCounters(): array
    {
        return $this->counters;
    }
    
    /**
     * Format bytes into human-readable format
     */
    private function formatBytes(int $bytes): string
    {
        $units = ['B', 'KB', 'MB', 'GB', 'TB'];
        $power = $bytes > 0 ? floor(log($bytes, 1024)) : 0;
        
        return round($bytes / (1024 ** $power), 2) . ' ' . $units[$power];
    }
}

Performance Logging Patterns

Key patterns for production performance monitoring:

  • Method-Level Timing: Automatic timer identification using magic constants
  • Memory Tracking: Memory usage deltas for memory leak detection
  • Counter Integration: Operation counting with contextual information
  • Threshold-Based Alerting: Log level adjustment based on execution time

Centralized Logger Factory

A logger factory centralizes configuration while providing specialized loggers for different application components. The factory pattern ensures consistent logging setup across services:

<?php

declare(strict_types=1);

namespace App\Logging;

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Handler\BrowserConsoleHandler;
use Monolog\Processor\PsrLogMessageProcessor;
use Monolog\Processor\IntrospectionProcessor;
use Monolog\Formatter\JsonFormatter;
use Monolog\Formatter\LineFormatter;
use App\Logging\Processors\DebugContextProcessor;
use Psr\Log\LoggerInterface;

/**
 * Factory for creating configured loggers with magic constants support
 */
class LoggerFactory
{
    private string $logDirectory;
    private bool $debugMode;
    private array $defaultChannels = [
        'app' => Logger::INFO,
        'database' => Logger::DEBUG,
        'security' => Logger::WARNING,
        'performance' => Logger::INFO,
        'api' => Logger::INFO,
    ];
    
    public function __construct(
        string $logDirectory = __DIR__ . '/../../var/logs',
        bool $debugMode = false
    ) {
        $this->logDirectory = $logDirectory;
        $this->debugMode = $debugMode;
        
        // Ensure log directory exists
        if (!is_dir($this->logDirectory)) {
            mkdir($this->logDirectory, 0755, true);
        }
    }
    
    /**
     * Create a logger for a specific channel
     */
    public function createLogger(
        string $channel,
        ?int $level = null
    ): LoggerInterface {
        $logger = new Logger($channel);
        $logLevel = $level ?? $this->defaultChannels[$channel] ?? Logger::INFO;
        
        // Add handlers based on environment
        $this->addHandlers($logger, $channel, $logLevel);
        
        // Add processors for enhanced context
        $this->addProcessors($logger);
        
        return $logger;
    }
    
    /**
     * Create enhanced logger with magic constants support
     */
    public function createEnhancedLogger(string $channel): EnhancedLogger
    {
        return new EnhancedLogger($channel);
    }
    
    /**
     * Create performance logger
     */
    public function createPerformanceLogger(string $channel = 'performance'): PerformanceLogger
    {
        $logger = $this->createLogger($channel, Logger::DEBUG);
        return new PerformanceLogger($logger);
    }
    
    /**
     * Add appropriate handlers based on channel and environment
     */
    private function addHandlers(Logger $logger, string $channel, int $level): void
    {
        // Main log file with rotation
        $mainHandler = new RotatingFileHandler(
            $this->logDirectory . "/{$channel}.log",
            7, // Keep 7 days
            $level
        );
        $mainHandler->setFormatter($this->createJsonFormatter());
        $logger->pushHandler($mainHandler);
        
        // Error-specific handler for serious issues
        if ($level <= Logger::ERROR) {
            $errorHandler = new StreamHandler(
                $this->logDirectory . '/errors.log',
                Logger::ERROR
            );
            $errorHandler->setFormatter($this->createJsonFormatter());
            $logger->pushHandler($errorHandler);
        }
        
        // Console handler for development
        if ($this->debugMode) {
            $consoleHandler = new StreamHandler('php://stdout', Logger::DEBUG);
            $consoleHandler->setFormatter($this->createLineFormatter());
            $logger->pushHandler($consoleHandler);
            
            // Browser console for web requests
            if (isset($_SERVER['HTTP_HOST'])) {
                $browserHandler = new BrowserConsoleHandler();
                $logger->pushHandler($browserHandler);
            }
        }
        
        // Channel-specific handlers
        $this->addChannelSpecificHandlers($logger, $channel);
    }
    
    /**
     * Add channel-specific handlers
     */
    private function addChannelSpecificHandlers(Logger $logger, string $channel): void
    {
        switch ($channel) {
            case 'security':
                // Security events should be logged separately
                $securityHandler = new StreamHandler(
                    $this->logDirectory . '/security.log',
                    Logger::INFO
                );
                $securityHandler->setFormatter($this->createJsonFormatter());
                $logger->pushHandler($securityHandler);
                break;
                
            case 'database':
                // Database queries and performance
                $dbHandler = new RotatingFileHandler(
                    $this->logDirectory . '/database.log',
                    30, // Keep longer for analysis
                    Logger::DEBUG
                );
                $dbHandler->setFormatter($this->createJsonFormatter());
                $logger->pushHandler($dbHandler);
                break;
                
            case 'api':
                // API requests and responses
                $apiHandler = new RotatingFileHandler(
                    $this->logDirectory . '/api.log',
                    14,
                    Logger::INFO
                );
                $apiHandler->setFormatter($this->createJsonFormatter());
                $logger->pushHandler($apiHandler);
                break;
        }
    }
    
    /**
     * Add processors for enhanced logging context
     */
    private function addProcessors(Logger $logger): void
    {
        // PSR-3 message processing for placeholder interpolation
        $logger->pushProcessor(new PsrLogMessageProcessor());
        
        // Introspection processor for basic caller info
        $logger->pushProcessor(new IntrospectionProcessor(
            Logger::DEBUG, // Only add introspection for debug and above
            ['Monolog\\', 'App\\Logging\\'] // Skip these namespaces
        ));
        
        // Custom debug context processor
        $logger->pushProcessor(new DebugContextProcessor(
            $this->debugMode, // Include stack trace in debug mode
            1 // Skip one frame to get actual caller
        ));
        
        // Add request context for web requests
        if (isset($_SERVER['REQUEST_METHOD'])) {
            $logger->pushProcessor(function ($record) {
                $record->extra['request_context'] = [
                    'method' => $_SERVER['REQUEST_METHOD'] ?? 'unknown',
                    'uri' => $_SERVER['REQUEST_URI'] ?? 'unknown',
                    'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
                    'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
                    'request_id' => $_SERVER['HTTP_X_REQUEST_ID'] ?? uniqid(),
                ];
                return $record;
            });
        }
    }
    
    /**
     * Create JSON formatter for structured logging
     */
    private function createJsonFormatter(): JsonFormatter
    {
        return new JsonFormatter(
            JsonFormatter::BATCH_MODE_JSON,
            true, // Include stack traces
            true  // Ignore empty context
        );
    }
    
    /**
     * Create line formatter for console output
     */
    private function createLineFormatter(): LineFormatter
    {
        $format = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n";
        $formatter = new LineFormatter($format, 'Y-m-d H:i:s');
        $formatter->allowInlineLineBreaks(true);
        $formatter->ignoreEmptyContextAndExtra(true);
        
        return $formatter;
    }
    
    /**
     * Get available log channels
     */
    public function getAvailableChannels(): array
    {
        return array_keys($this->defaultChannels);
    }
    
    /**
     * Set debug mode
     */
    public function setDebugMode(bool $debugMode): void
    {
        $this->debugMode = $debugMode;
    }
}

Factory Architecture Benefits

  • Channel Separation: Different log files for different concerns
  • Environment Adaptation: Debug vs production handler configuration
  • Processor Consistency: Uniform context enrichment across loggers
  • Handler Specialization: Channel-specific output formatting and storage

Real-World Implementation Examples

Practical examples demonstrate magic constants in production scenarios:

<?php

declare(strict_types=1);

require_once 'vendor/autoload.php';

use App\Logging\LoggerFactory;
use App\Services\UserService;
use App\Logging\PerformanceLogger;

// Initialize the logging system
$loggerFactory = new LoggerFactory(__DIR__ . '/logs', true);

// Create different types of loggers
$appLogger = $loggerFactory->createLogger('app');
$performanceLogger = $loggerFactory->createPerformanceLogger();

// Example 1: Basic logging with magic constants
function demonstrateBasicLogging()
{
    global $appLogger;
    
    $appLogger->info('Function started', [
        'function' => __FUNCTION__,
        'file' => __FILE__,
        'line' => __LINE__,
    ]);
    
    // Simulate some work
    sleep(1);
    
    $appLogger->info('Function completed', [
        'function' => __FUNCTION__,
        'execution_time' => '1 second',
        'line' => __LINE__,
    ]);
}

// Example 2: Service with integrated logging
$userService = new UserService($appLogger);

try {
    // Create a user - this will demonstrate method-level logging
    $user = $userService->createUser([
        'email' => 'john.doe@example.com',
        'name' => 'John Doe'
    ]);
    
    echo "Created user: {$user['id']}\n";
    
    // Retrieve the user
    $retrievedUser = $userService->getUser($user['id']);
    echo "Retrieved user: {$retrievedUser['name']}\n";
    
    // Try to get a non-existent user
    $nonExistentUser = $userService->getUser('non-existent-id');
    
} catch (Exception $e) {
    echo "Error: {$e->getMessage()}\n";
}

// Example 3: Performance logging with timing
function demonstratePerformanceLogging()
{
    global $performanceLogger;
    
    // Start timing with automatic identification
    $timerId = $performanceLogger->startTimer(
        null, // Auto-generate ID
        __FUNCTION__,
        __CLASS__ ?? 'global',
        __LINE__
    );
    
    // Simulate database operations
    $performanceLogger->incrementCounter('database_queries', 1, __FUNCTION__);
    usleep(250000); // 250ms
    
    $performanceLogger->incrementCounter('database_queries', 2, __FUNCTION__);
    usleep(150000); // 150ms
    
    // Log a performance snapshot
    $performanceLogger->logSnapshot(
        'After database operations',
        __FUNCTION__,
        __CLASS__ ?? 'global',
        __LINE__
    );
    
    // Stop timing
    $metrics = $performanceLogger->stopTimer($timerId, [
        'operations_performed' => 'Database queries and cache checks',
        'queries_executed' => 3,
    ]);
    
    echo "Performance metrics: " . json_encode($metrics, JSON_PRETTY_PRINT) . "\n";
}

// Example 4: Error handling with context
function demonstrateErrorLogging()
{
    global $appLogger;
    
    try {
        // Simulate an error condition
        $data = json_decode('invalid json', true);
        
        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new RuntimeException('JSON parsing failed: ' . json_last_error_msg());
        }
        
    } catch (Exception $e) {
        $appLogger->error('JSON parsing error occurred', [
            'error_message' => $e->getMessage(),
            'error_code' => $e->getCode(),
            'error_file' => $e->getFile(),
            'error_line' => $e->getLine(),
            'function' => __FUNCTION__,
            'file' => __FILE__,
            'line' => __LINE__,
            'input_data' => 'invalid json',
            'json_error_code' => json_last_error(),
        ]);
        
        // Re-throw or handle as needed
        throw $e;
    }
}

// Example 5: Namespace-aware logging
namespace App\Examples {
    
    class NamespaceExample
    {
        private $logger;
        
        public function __construct($logger)
        {
            $this->logger = $logger;
            
            $this->logger->info('Class instantiated', [
                'class' => __CLASS__,
                'namespace' => __NAMESPACE__,
                'method' => __METHOD__,
                'file' => __FILE__,
                'line' => __LINE__,
            ]);
        }
        
        public function doSomething(): void
        {
            $this->logger->debug('Method execution started', [
                'method' => __METHOD__,
                'class' => __CLASS__,
                'namespace' => __NAMESPACE__,
                'line' => __LINE__,
            ]);
            
            // Simulate work
            usleep(100000);
            
            $this->logger->debug('Method execution completed', [
                'method' => __METHOD__,
                'line' => __LINE__,
            ]);
        }
    }
}

// Run examples
echo "Running logging examples...\n\n";

echo "1. Basic logging:\n";
demonstrateBasicLogging();

echo "\n2. Performance logging:\n";
demonstratePerformanceLogging();

echo "\n3. Namespace-aware logging:\n";
$namespaceExample = new App\Examples\NamespaceExample($appLogger);
$namespaceExample->doSomething();

echo "\n4. Error logging:\n";
try {
    demonstrateErrorLogging();
} catch (Exception $e) {
    echo "Caught and logged error: {$e->getMessage()}\n";
}

echo "\nAll examples completed. Check the log files in the logs directory.\n";

Production Logging Strategies

Effective production logging balances information depth with performance impact:

  • Structured JSON: Machine-readable logs for analysis tools
  • Log Level Management: Environment-appropriate verbosity levels
  • Context Minimization: Essential information without overwhelming detail
  • Performance Monitoring: Resource usage tracking without overhead

Security and Sensitive Data Handling

Magic constants enhance security logging by providing precise context for security events. However, careful consideration prevents sensitive data exposure:

Security Logging Best Practices

  • Context Filtering: Remove passwords, tokens, and personal data from context
  • File Path Sanitization: Avoid exposing internal directory structures in logs
  • Stack Trace Limits: Restrict stack trace depth to prevent information disclosure
  • Access Control: Secure log file permissions and access patterns

Sensitive Data Redaction

Implement context processors that sanitize sensitive data while preserving debugging value:

// Example context sanitization
$sanitizedContext = array_map(function($value, $key) {
    if (in_array($key, ['password', 'token', 'secret'])) {
        return '[REDACTED]';
    }
    return $value;
}, $context, array_keys($context));

Testing and Debugging Strategies

Magic constants significantly improve debugging by providing automatic context without manual instrumentation. Testing logging systems requires mock loggers and context validation:

Testing Approaches

  • Mock Logger Testing: Verify log messages and context without file operations using PHPUnit
  • Context Validation: Assert magic constants provide expected values using PHPUnit assertions
  • Performance Testing: Measure logging overhead in high-throughput scenarios using PHPBench
  • Integration Testing: Validate end-to-end logging pipeline functionality with PHPUnit

Development Environment Configuration

Development logging should maximize debugging information while maintaining performance:

// Development logger configuration
$logger = $loggerFactory->createLogger('app', Logger::DEBUG);
$logger->pushProcessor(new DebugContextProcessor(true, 0)); // Include full stack traces

Performance Considerations

Magic constants are resolved at compile time, making them performant for logging. However, context building and log processing can impact performance in high-throughput applications:

Optimization Strategies

  • Log Level Filtering: Disable debug logging in production
  • Lazy Context Building: Build expensive context only when needed
  • Asynchronous Logging: Queue log entries for background processing using message queues
  • Selective Processing: Apply expensive processors only to specific channels

Memory Management

Large context arrays and stack traces can consume significant memory. Implement context limits and cleanup strategies:

// Memory-conscious logging
$context = array_slice($fullContext, 0, 50); // Limit context size
$logger->info($message, $context);
unset($context); // Explicit cleanup

Integration with Modern PHP Ecosystems

Magic constants logging integrates seamlessly with popular PHP frameworks and tools:

Framework Integration

Monitoring and Observability

Structured logs with magic constants integrate with modern observability platforms:

  • ELK Stack: Elasticsearch indexing of structured JSON logs
  • Grafana: Visualization of performance metrics from logs
  • Sentry: Error tracking with rich context from magic constants
  • DataDog: Application performance monitoring with log correlation

Future-Proofing and Evolution

As PHP evolves, magic constants remain stable while logging ecosystems advance. Consider these trends for long-term maintainability:

Emerging Patterns

  • OpenTelemetry: Distributed tracing with magic constants context
  • Structured Logging Standards: Consistent JSON schemas across services
  • AI-Powered Log Analysis: Machine learning on rich context data
  • Real-Time Log Streaming: Event-driven logging architectures

Migration Strategies

Plan for logging system evolution while maintaining backward compatibility:

  • Version Compatibility: Maintain support for older Monolog versions
  • Context Schema Evolution: Additive changes to log context structure
  • Handler Migration: Gradual transition to new log storage systems
  • Performance Monitoring: Track logging system performance impact

Implementation Checklist

Successful magic constants logging implementation requires systematic approach:

Setup Phase

  • Install Monolog 3.x with proper version constraints
  • Configure logger factory with environment-specific handlers
  • Implement custom processors for magic constants integration
  • Set up log rotation and retention policies

Development Phase

  • Create logging traits for consistent context injection
  • Implement performance logging for critical methods
  • Add security event logging with context sanitization
  • Configure development vs production logging levels

Production Phase

  • Monitor logging performance and memory usage
  • Implement log analysis and alerting systems
  • Regular log cleanup and archival processes
  • Security audit of log access and permissions

Conclusion

PHP magic constants transform logging from manual instrumentation to automatic context enrichment. Combined with Monolog's processing capabilities and PSR-3 standards, they create maintainable logging architectures that scale with application complexity.

The key to successful implementation lies in balancing information richness with performance impact, leveraging structured logging for observability, and maintaining security awareness in context handling. Magic constants provide the foundation for logging systems that grow with your application while maintaining debugging effectiveness.

As PHP applications become more distributed and complex, automatic context generation through magic constants becomes essential for effective debugging and monitoring. The patterns and implementations shown here provide a solid foundation for production-ready logging systems that support both development productivity and operational visibility.