A comprehensive application framework component for PHP 8.4+ that provides base classes, configuration management, event handling, and lifecycle management for building robust applications with the Neuron framework.
- Installation
- Quick Start
- Core Features
- Application Base Class
- Configuration Management
- Event System
- Initializers
- Command Line Applications
- Logging
- Error Handling
- Registry Pattern
- Testing
- Best Practices
- More Information
- PHP 8.4 or higher
- Extensions: curl, json
- Composer
composer require neuron-php/applicationuseNeuron\Application\Base;
useNeuron\Data\Settings\Source\Yaml;
class MyApplication extends Base
{
protectedfunctiononStart(): bool
{
\Neuron\Log\Log::info('Application starting...');
returntrue; // Return false to abort
}
protectedfunctiononRun(): void
{
// Main application logicecho"Running application v" . $this->getVersion() . "\n";
}
protectedfunctiononStop(): void
{
\Neuron\Log\Log::info('Application stopped');
}
}
// Bootstrap and run$settings = newYaml('config/neuron.yaml');
$app = newMyApplication('1.0.0', $settings);
$app->run();- Application Lifecycle Management: onStart, onRun, onStop, onFinish hooks
- Configuration System: Flexible settings from YAML, INI, ENV sources
- Event-Driven Architecture: Global event emitter with listener configuration
- Initializer System: Automatic loading and execution of initialization code
- Logging Integration: Built-in logging with multiple destinations
- Error Handling: Comprehensive error and fatal error handlers
- Registry Pattern: Global object storage and retrieval
- Command Line Support: Specialized base class for CLI applications
- Settings Fallback: Automatic fallback to environment variables
The Base class provides core application functionality:
class MyApp extends Base
{
/** * Called before the application starts * Return false to abort startup */protectedfunctiononStart(): bool
{
// Initialize resources$db = $this->initDatabase();
$this->setRegistryObject('database', $db);
// Load configurationif (!$this->loadConfiguration()) {
Log::error('Configuration failed');
returnfalse; // Abort startup
}
returntrue;
}
/** * Main application logic */protectedfunctiononRun(): void
{
// Process requests, run main loop, etc.$this->processRequests();
}
/** * Called when application is stopping */protectedfunctiononStop(): void
{
// Cleanup resources$this->closeConnections();
}
/** * Called after everything else */protectedfunctiononFinish(): void
{
Log::info('Application finished');
}
/** * Handle errors */protectedfunctiononError($level, $message, $file, $line): void
{
Log::error("Error: $message in $file:$line");
}
/** * Handle fatal errors */protectedfunctiononFatal(): void
{
$error = error_get_last();
Log::fatal('Fatal error: ' . $error['message']);
$this->setCrashed(true);
}
}// Create and configure$app = newMyApp('1.0.0', newYaml('neuron.yaml'));
// Set parameters (e.g., from command line)$app->setParameters($_SERVER['argv']);
// Run with optional parameters$app->run(['--verbose', '--mode=production']);The application supports multiple configuration sources through the ISettingSource interface:
useNeuron\Data\Settings\Source\Yaml;
useNeuron\Data\Settings\Source\Ini;
useNeuron\Data\Settings\Source\Env;
// YAML configuration$yamlSource = newYaml('config/app.yaml');
$app = newMyApp('1.0.0', $yamlSource);
// INI configuration$iniSource = newIni('config/app.ini');
$app = newMyApp('1.0.0', $iniSource);
// Environment variables (fallback)$envSource = newEnv();
$app = newMyApp('1.0.0', $envSource);
// No configuration (defaults to environment)$app = newMyApp('1.0.0');Example neuron.yaml:
system:
timezone: America/New_Yorkbase_path: /appenvironment: productionlogging:
destination: \Neuron\Log\Destination\Fileformat: \Neuron\Log\Format\PlainTextfile: app.loglevel: infoevents:
listeners_path: app/Listenersdatabase:
host: localhostport: 3306name: myappusername: dbuserpassword: secretcache:
enabled: truedriver: redisttl: 3600class MyApp extends Base
{
protectedfunctiononStart(): bool
{
// Get settings$dbHost = $this->getSetting('database', 'host');
$cacheEnabled = $this->getSetting('cache', 'enabled');
// Set runtime settings$this->setSetting('app', 'mode', 'maintenance');
// Get the SettingManager instance$settings = $this->getSettingManager();
if ($settings) {
$source = $settings->getSource();
// Work with the source directly
}
returntrue;
}
}// Configuration with environment fallback$yamlSource = newYaml('neuron.yaml');
$envFallback = newEnv();
$settings = newSettingManager($yamlSource);
$settings->setFallback($envFallback);
$app = newMyApp('1.0.0', $settings);
// Now settings check YAML first, then environment variables$apiKey = $app->getSetting('api', 'key'); // Checks neuron.yaml then API_KEY env varThe application provides a global event emitter through the CrossCutting\Event class:
useNeuron\Application\CrossCutting\Event;
// Emit events from anywhere
Event::emit(newUserRegisteredEvent($user));
// In your applicationclass MyApp extends Base
{
protectedfunctiononStart(): bool
{
// Initialize event system$this->initEvents();
// Add listeners programmatically
Event::addListener(
UserRegisteredEvent::class,
newWelcomeEmailListener()
);
returntrue;
}
}Configure event listeners via YAML (event-listeners.yaml):
listeners:
UserRegisteredEvent:
- App\Listeners\SendWelcomeEmail
- App\Listeners\UpdateAnalytics
- App\Listeners\NotifyAdminsOrderCompletedEvent:
- App\Listeners\UpdateInventory
- App\Listeners\SendInvoice
- App\Listeners\ProcessCommissionInitializers are classes that run during application startup for bootstrapping:
Create files in app/Initializers/:
// app/Initializers/DatabaseInitializer.phpnamespaceApp\Initializers;
useNeuron\Patterns\IRunnable;
class DatabaseInitializer implements IRunnable
{
publicfunctionrun(): void
{
// Initialize database connections$db = newDatabaseConnection(
$_ENV['DB_HOST'],
$_ENV['DB_NAME']
);
$this->setRegistryObject('database', $db);
}
}Initializers are automatically loaded and executed during onStart():
They are atomic instances of classes implementing IRunnable and enable modular startup logic.
class InitTest implements IRunnable
{
publicfunctionrun( array$Argv = [] ): mixed
{
Registry::getInstance()
->set( 'examples\Initializers\InitTest', 'Hello World!' );
returntrue;
}
}The CommandLineBase class extends Base with CLI-specific features:
useNeuron\Application\CommandLineBase;
class CliApp extends CommandLineBase
{
protectedfunctiononRun(): void
{
$args = $this->getParameters();
// Parse command line arguments$command = $args[1] ?? 'help';
switch ($command) {
case'process':
$this->processData();
break;
case'import':
$this->importData();
break;
default:
$this->showHelp();
}
}
privatefunctionshowHelp(): void
{
echo"Usage: php app.php [command]\n";
echo"Commands:\n";
echo" process - Process data\n";
echo" import - Import data\n";
}
}
// Run CLI app$app = newCliApp('1.0.0');
$app->setParameters($argv);
$app->run();The application automatically initializes logging based on configuration:
useNeuron\Log\Log;
class MyApp extends Base
{
protectedfunctiononStart(): bool
{
// Logging is already initialized from config// Access the Log singleton directly
Log::info('Application starting');
Log::debug('Debug message');
Log::warning('Warning message');
Log::error('Error occurred');
returntrue;
}
}class MyApp extends Base
{
publicfunction__construct($version, $source = null)
{
parent::__construct($version, $source);
// Enable error handling$this->_HandleErrors = true;
$this->_HandleFatal = true;
}
protectedfunctiononError($level, $message, $file, $line): void
{
// Custom error handling
Log::error("Error [$level]: $message in $file:$line");
// Send alert for critical errorsif ($level === E_ERROR) {
$this->sendAlert("Critical error: $message");
}
}
protectedfunctiononFatal(): void
{
$error = error_get_last();
// Log fatal error
\Neuron\Log\Log::fatal('Fatal: ' . $error['message']);
// Set crashed state$this->setCrashed(true);
// Cleanup before exit$this->emergencyCleanup();
}
}$app = newMyApp('1.0.0');
$app->run();
if ($app->getCrashed()) {
// Handle crash recoveryfile_put_contents('crash.log', date('Y-m-d H:i:s') . ' - Application crashed' . PHP_EOL, FILE_APPEND);
// Restart or alertexec('php restart.php');
}class MyApp extends Base
{
protectedfunctiononStart(): bool
{
// Store objects in registry$this->setRegistryObject('database', $dbConnection);
$this->setRegistryObject('cache', $cacheManager);
$this->setRegistryObject('api.client', $apiClient);
// Retrieve objects$db = $this->getRegistryObject('database');
$cache = $this->getRegistryObject('cache');
// Direct registry access$registry = Registry::getInstance();
$registry->set('app.mode', 'production');
$mode = $registry->get('app.mode');
returntrue;
}
}// Use namespaced keys$app->setRegistryObject('services.email', $emailService);
$app->setRegistryObject('services.payment', $paymentService);
$app->setRegistryObject('repositories.user', $userRepo);
// Store configurations$app->setRegistryObject('config.api.keys', $apiKeys);
$app->setRegistryObject('config.features', $featureFlags);
// Store runtime state$app->setRegistryObject('runtime.start_time', microtime(true));
$app->setRegistryObject('runtime.request_count', 0);usePHPUnit\Framework\TestCase;
class ApplicationTest extends TestCase
{
publicfunctiontestApplicationStartup(): void
{
$settings = newMemory();
$settings->set('system', 'timezone', 'UTC');
$app = newMyApp('1.0.0', $settings);
// Test startup$reflection = newReflectionMethod($app, 'onStart');
$reflection->setAccessible(true);
$result = $reflection->invoke($app);
$this->assertTrue($result);
}
publicfunctiontestErrorHandling(): void
{
$app = newMyApp('1.0.0');
$app->enableErrorHandling(true);
// Trigger error$reflection = newReflectionMethod($app, 'onError');
$reflection->setAccessible(true);
$reflection->invoke($app, E_WARNING, 'Test error', 'test.php', 100);
// Assert error was logged$this->assertStringContainsString('Test error', $this->getLogContent());
}
}class MockApplication extends Base
{
publicbool$started = false;
publicbool$ran = false;
publicbool$stopped = false;
protectedfunctiononStart(): bool
{
$this->started = true;
returntrue;
}
protectedfunctiononRun(): void
{
$this->ran = true;
}
protectedfunctiononStop(): void
{
$this->stopped = true;
}
}
// Test lifecycle$app = newMockApplication('1.0.0');
$app->run();
$this->assertTrue($app->started);
$this->assertTrue($app->ran);
$this->assertTrue($app->stopped);class ProductionApp extends Base
{
protectedfunctiononStart(): bool
{
// 1. Initialize critical services firstif (!$this->initializeDatabase()) {
returnfalse;
}
// 2. Load configuration$this->loadConfiguration();
// 3. Set up logging$this->setupLogging();
// 4. Initialize events$this->initEvents();
// 5. Run initializers$this->executeInitializers();
// 6. Validate environmentif (!$this->validateEnvironment()) {
$this->log('Environment validation failed', 'error');
returnfalse;
}
returntrue;
}
privatefunctionvalidateEnvironment(): bool
{
// Check required settings$required = ['database.host', 'api.key', 'cache.driver'];
foreach ($requiredas$setting) {
[$section, $key] = explode('.', $setting);
if (!$this->getSetting($section, $key)) {
\Neuron\Log\Log::error("Missing required setting: $setting");
returnfalse;
}
}
returntrue;
}
}useNeuron\Data\Objects\Version;
// Load version from file$version = newVersion();
$version->loadFromFile('.version.json');
$app = newMyApp($version->getAsString());
// Access version in appecho"Running version: " . $app->getVersion();- Neuron Framework: neuronphp.com
- GitHub: github.com/neuron-php/application
- Packagist: packagist.org/packages/neuron-php/application