---
title: No Business Logic In Constructors
impact: HIGH
impactDescription: ensures predictable object initialization
tags: constructor, initialization, side-effects, patterns, quality, php
---

## No Business Logic In Constructors

Constructors should be used exclusively for assigning dependencies and initializing basic object state. Including complex business logic, file I/O, or API calls in constructors makes code unpredictable, harder to test, and can lead to unexpected side effects during object instantiation.

**Incorrect (heavy logic in constructor):**

```php
class UserService {
    private array $config;

    public function __construct(string $configPath) {
        // BAD: File I/O in constructor
        if (!file_exists($configPath)) {
            throw new Exception("Config not found");
        }
        $this->config = json_decode(file_get_contents($configPath), true);

        // BAD: Establishing connections or complex logic
        $this->db = new PDO($this->config['dsn']);
        
        // BAD: Side effects
        Log::info("UserService started");
    }
}
```

**Correct (assignments only or Factory pattern):**

```php
class UserService {
    public function __construct(
        private array $config,
        private PDO $db
    ) {
        // Assignments only - no side effects
    }

    /**
     * Factory method for controlled initialization
     */
    public static function create(string $configPath): self {
        $config = json_decode(file_get_contents($configPath), true);
        $db = new PDO($config['dsn']);
        
        Log::info("UserService initialized via factory");
        
        return new self($config, $db);
    }
}

// Usage
$service = UserService::create('/path/to/config.json');
```

**Why avoid logic in constructors?**
- **Testability**: You cannot easily mock the behavior of a constructor.
- **Predictability**: `new MyClass()` should be fast and side-effect free.
- **Error Handling**: Exceptions in constructors can leave objects in an inconsistent state or be difficult to handle during DI container resolution.
- **Coupling**: It often forces the class to know how to create its own dependencies.

**Tools:** PHPStan, Psalm, PR review
