Some checks are pending
Telegram Mini App Shop Builder / Compute version metadata (push) Waiting to run
Telegram Mini App Shop Builder / Run Frontend tests (push) Waiting to run
Telegram Mini App Shop Builder / Run Backend tests (push) Waiting to run
Telegram Mini App Shop Builder / Run PHP_CodeSniffer (push) Waiting to run
Telegram Mini App Shop Builder / Build module. (push) Blocked by required conditions
Telegram Mini App Shop Builder / release (push) Blocked by required conditions
244 lines
4.0 KiB
Markdown
244 lines
4.0 KiB
Markdown
# PHP Code Style Rules
|
||
|
||
## PHP Version
|
||
|
||
The project supports PHP 7.4+
|
||
|
||
## PSR Standards
|
||
|
||
- **PSR-1**: Basic Coding Standard
|
||
- **PSR-4**: Autoloading Standard
|
||
- **PSR-12**: Extended Coding Style
|
||
|
||
## Code Style
|
||
|
||
### Type Declarations
|
||
|
||
```php
|
||
// ✅ Correct – strict typing
|
||
public function getCustomers(Request $request): JsonResponse
|
||
{
|
||
$id = (int) $request->get('id');
|
||
return new JsonResponse(['data' => $customers]);
|
||
}
|
||
|
||
// ❌ Incorrect – no types
|
||
public function getCustomers($request)
|
||
{
|
||
return ['data' => $customers];
|
||
}
|
||
```
|
||
|
||
### Nullable Types
|
||
|
||
```php
|
||
// ✅ Correct
|
||
public function findById(?int $id): ?array
|
||
{
|
||
if ($id === null) {
|
||
return null;
|
||
}
|
||
return $this->query->where('id', '=', $id)->firstOrNull();
|
||
}
|
||
```
|
||
|
||
### Strict Types
|
||
|
||
Always use `declare(strict_types=1);`:
|
||
|
||
```php
|
||
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace App\Services;
|
||
```
|
||
|
||
### Array Syntax
|
||
|
||
```php
|
||
// ✅ Preferred – short syntax
|
||
$array = ['key' => 'value'];
|
||
|
||
// ❌ Do not use
|
||
$array = array('key' => 'value');
|
||
```
|
||
|
||
### String Interpolation
|
||
|
||
```php
|
||
// ✅ Preferred
|
||
$message = "User {$userId} not found";
|
||
|
||
// ✅ Alternative
|
||
$message = sprintf('User %d not found', $userId);
|
||
```
|
||
|
||
### Arrow Functions (PHP 7.4+)
|
||
|
||
```php
|
||
// ✅ For simple operations
|
||
$filtered = array_filter($items, fn($item) => $item->isActive());
|
||
|
||
// ❌ For complex logic – use regular functions
|
||
```
|
||
|
||
### Nullsafe Operator (PHP 8.0+)
|
||
|
||
```php
|
||
// ✅ For 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 with visibility modifier
|
||
private string $tableName;
|
||
private Builder $builder;
|
||
```
|
||
|
||
## Documentation
|
||
|
||
### PHPDoc
|
||
|
||
```php
|
||
/**
|
||
* @throws ValidationException If parameters are invalid
|
||
*/
|
||
public function getCustomers(Request $request): JsonResponse
|
||
{
|
||
// ...
|
||
}
|
||
```
|
||
|
||
### Inline Comments
|
||
|
||
```php
|
||
// ✅ Useful comments
|
||
// Apply filters to calculate total number of records
|
||
$countQuery = $this->buildCountQuery($filters);
|
||
|
||
// ❌ Obvious comments
|
||
// Get data
|
||
$data = $this->getData();
|
||
```
|
||
|
||
## Error Handling
|
||
|
||
### Exceptions
|
||
|
||
```php
|
||
// ✅ Specific exceptions
|
||
if (!$userId) {
|
||
throw new InvalidArgumentException('User ID is required');
|
||
}
|
||
|
||
// ✅ Logging
|
||
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
|
||
// ✅ Correct
|
||
$customers = $this->builder->newQuery()
|
||
->select(['id', 'name', 'email'])
|
||
->from('acmeshop_customers')
|
||
->where('status', '=', 'active')
|
||
->orderBy('created_at', 'DESC')
|
||
->get();
|
||
|
||
// In edge cases raw SQL may be used
|
||
$result = $this->database->query("SELECT * FROM acmeshop_customers");
|
||
```
|
||
|
||
### Parameter Binding
|
||
|
||
```php
|
||
// ✅ Query Builder automatically binds parameters
|
||
$query->where('name', 'LIKE', "%{$search}%");
|
||
|
||
// ❌ Never concatenate values into SQL, avoid SQL Injection.
|
||
```
|
||
|
||
## Array Access
|
||
|
||
### Safe Array Access
|
||
|
||
```php
|
||
// ✅ Use Arr::get()
|
||
use Acme\ECommerceFramework\Support\Arr;
|
||
|
||
$value = Arr::get($data, 'key', 'default');
|
||
|
||
// ❌ Unsafe
|
||
$value = $data['key']; // may trigger an error
|
||
```
|
||
|
||
## Return Types
|
||
|
||
```php
|
||
// ✅ Always specify return type
|
||
public function getData(): array {}
|
||
public function findById(int $id): ?array {}
|
||
public function process(): void {}
|
||
|
||
// ❌ Without type
|
||
public function getData() {}
|
||
```
|
||
|
||
## Visibility Modifiers
|
||
|
||
```php
|
||
// ✅ Always specify visibility modifier
|
||
private string $tableName;
|
||
protected Builder $builder;
|
||
public function getData(): array {}
|
||
```
|
||
|