# PHP Code Style Rules

## PHP Version

Проект поддерживает PHP 7.4+

## PSR Standards

- **PSR-1**: Basic Coding Standard
- **PSR-4**: Autoloading Standard
- **PSR-12**: Extended Coding Style

## Code Style

### Type Declarations

```php
// ✅ Правильно - строгая типизация
public function getCustomers(Request $request): JsonResponse
{
    $id = (int) $request->get('id');
    return new JsonResponse(['data' => $customers]);
}

// ❌ Неправильно - без типов
public function getCustomers($request)
{
    return ['data' => $customers];
}
```

### Nullable Types

```php
// ✅ Правильно
public function findById(?int $id): ?array
{
    if ($id === null) {
        return null;
    }
    return $this->query->where('id', '=', $id)->firstOrNull();
}
```

### Strict Types

Всегда используй `declare(strict_types=1);`:

```php
<?php

declare(strict_types=1);

namespace App\Services;
```

### Array Syntax

```php
// ✅ Предпочтительно - короткий синтаксис
$array = ['key' => 'value'];

// ❌ Не использовать
$array = array('key' => 'value');
```

### String Interpolation

```php
// ✅ Предпочтительно
$message = "User {$userId} not found";

// ✅ Альтернатива
$message = sprintf('User %d not found', $userId);
```

### Arrow Functions (PHP 7.4+)

```php
// ✅ Для простых операций
$filtered = array_filter($items, fn($item) => $item->isActive());

// ❌ Для сложной логики - используй обычные функции
```

### Nullsafe Operator (PHP 8.0+)

```php
// ✅ Для PHP 7.4
$name = $user && $user->profile ? $user->profile->name : null;
```

## Naming Conventions

### Classes

```php
// ✅ PascalCase
class TelegramCustomerService {}
class UserRepository {}
```

### Methods

```php
// ✅ camelCase
public function getCustomers(): array {}
public function saveOrUpdate(array $data): array {}
```

### Variables

```php
// ✅ camelCase
$customerData = [];
$totalRecords = 0;
```

### Constants

```php
// ✅ UPPER_SNAKE_CASE
private const MAX_RETRIES = 3;
public const DEFAULT_PAGE_SIZE = 20;
```

### Private Properties

```php
// ✅ camelCase с модификатором доступа
private string $tableName;
private Builder $builder;
```

## Documentation

### PHPDoc

```php
/**
 * @throws ValidationException Если параметры невалидны
 */
public function getCustomers(Request $request): JsonResponse
{
    // ...
}
```

### Inline Comments

```php
// ✅ Полезные комментарии
// Применяем фильтры для подсчета общего количества записей
$countQuery = $this->buildCountQuery($filters);

// ❌ Очевидные комментарии
// Получаем данные
$data = $this->getData();
```

## Error Handling

### Exceptions

```php
// ✅ Специфичные исключения
if (!$userId) {
    throw new InvalidArgumentException('User ID is required');
}

// ✅ Логирование
try {
    $result = $this->service->process();
} catch (Exception $e) {
    $this->logger->error('Processing failed', [
        'exception' => $e,
        'context' => $context,
    ]);
    throw new ProcessingException('Failed to process', 0, $e);
}
```

## Query Builder Usage

### Always Use Query Builder

```php
// ✅ Правильно
$customers = $this->builder->newQuery()
    ->select(['id', 'name', 'email'])
    ->from('telecart_customers')
    ->where('status', '=', 'active')
    ->orderBy('created_at', 'DESC')
    ->get();

// В крайних случаях можно использовать прямые SQL
$result = $this->database->query("SELECT * FROM telecart_customers");
```

### Parameter Binding

```php
// ✅ Query Builder автоматически биндит параметры
$query->where('name', 'LIKE', "%{$search}%");

// ❌ Никогда не конкатенируй значения в SQL, избегай SQL Injection.
```

## Array Access

### Safe Array Access

```php
// ✅ Используй Arr::get()
use Openguru\OpenCartFramework\Support\Arr;

$value = Arr::get($data, 'key', 'default');

// ❌ Небезопасно
$value = $data['key']; // может вызвать ошибку
```

## Return Types

```php
// ✅ Всегда указывай return type
public function getData(): array {}
public function findById(int $id): ?array {}
public function process(): void {}

// ❌ Без типа
public function getData() {}
```

## Visibility Modifiers

```php
// ✅ Всегда указывай модификатор доступа
private string $tableName;
protected Builder $builder;
public function getData(): array {}
```

