- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
14 KiB
14 KiB
Coding Standards
Diese Dokumentation beschreibt die Coding Standards, die bei der Entwicklung des Frameworks eingehalten werden sollten. Die Einhaltung dieser Standards gewährleistet einen konsistenten Codestil im gesamten Projekt und erleichtert die Zusammenarbeit zwischen Entwicklern.
PHP-Standards
PSR-Standards
Das Framework folgt den PHP Standards Recommendations (PSR) des PHP Framework Interop Group (PHP-FIG):
- PSR-1: Basic Coding Standard
- PSR-2: Coding Style Guide und PSR-12: Extended Coding Style (ersetzt PSR-2)
- PSR-4: Autoloading Standard
Allgemeine Richtlinien
Dateien
- Dateien MÜSSEN die UTF-8-Kodierung ohne BOM verwenden.
- Dateien SOLLTEN entweder Deklarationen (Klassen, Funktionen, Konstanten) ODER Nebeneffekte (z.B. Ausgaben, Änderungen an .ini-Einstellungen) enthalten, aber NICHT beides.
- Dateinamen MÜSSEN
PascalCasefür Klassen verwenden (z.B.UserController.php). - Alle PHP-Dateien MÜSSEN mit einer einzelnen leeren Zeile enden.
PHP-Tags
- PHP-Code MUSS die langen Tags
<?php ?>oder die kurzen Echo-Tags<?= ?>verwenden. - Die schließenden Tags
?>SOLLTEN bei Dateien, die nur PHP enthalten, weggelassen werden.
Zeichenkodierung und Zeilenumbrüche
- Der Code MUSS UTF-8 ohne BOM verwenden.
- Zeilenumbrüche MÜSSEN im Unix-Format (LF) sein.
Namenskonventionen
Namespaces
- Namespaces MÜSSEN
PascalCaseverwenden. - Der Basis-Namespace für das Framework ist
App\Framework. - Der Basis-Namespace für anwendungsspezifischen Code ist
App\Application.
namespace App\Framework\Http;
namespace App\Application\Controllers;
Klassen
- Klassennamen MÜSSEN
PascalCaseverwenden. - Schnittstellen MÜSSEN mit dem Suffix
Interfaceenden. - Abstrakte Klassen SOLLTEN mit dem Präfix
Abstractbeginnen. - Traits SOLLTEN mit dem Suffix
Traitenden.
class UserController
interface RepositoryInterface
abstract class AbstractController
trait LoggableTrait
Methoden und Funktionen
- Methoden- und Funktionsnamen MÜSSEN
camelCaseverwenden. - Methoden SOLLTEN Verben sein, die ihre Aktion beschreiben.
public function getUserById(int $id): ?User
public function createUser(array $data): User
public function updateUserProfile(User $user, array $data): bool
Eigenschaften und Variablen
- Eigenschaften und Variablen MÜSSEN
camelCaseverwenden. - Private und geschützte Eigenschaften SOLLTEN NICHT mit einem Unterstrich beginnen.
private string $firstName;
protected int $itemCount;
public bool $isActive;
Konstanten
- Klassenkonstanten MÜSSEN in
UPPER_CASEmit Unterstrichen als Trennzeichen definiert werden.
public const MAX_ATTEMPTS = 5;
private const DEFAULT_TIMEOUT = 30;
Enums
- Enum-Namen MÜSSEN
PascalCaseverwenden. - Enum-Werte MÜSSEN
UPPER_CASEmit Unterstrichen als Trennzeichen verwenden.
enum HttpMethod
{
case GET;
case POST;
case PUT;
case DELETE;
}
enum LogLevel: string
{
case DEBUG = 'debug';
case INFO = 'info';
case WARNING = 'warning';
case ERROR = 'error';
}
Codestruktur
Klassen
- Jede Klasse MUSS in einer eigenen Datei definiert werden.
- Die Struktur einer Klasse SOLLTE wie folgt sein:
- Namespace-Deklaration
- Verwendete Imports (alphabetisch sortiert)
- Klassendokumentation (PHPDoc)
- Klassendeklaration
- Konstanten (öffentlich, geschützt, privat)
- Eigenschaften (öffentlich, geschützt, privat)
- Konstruktor und Destruktor
- Öffentliche Methoden
- Geschützte Methoden
- Private Methoden
<?php
namespace App\Framework\Database;
use App\Framework\Contracts\ConnectionInterface;
use App\Framework\Exceptions\DatabaseException;
/**
* Database connection manager.
*/
class Connection implements ConnectionInterface
{
/**
* Default connection timeout in seconds.
*/
public const DEFAULT_TIMEOUT = 30;
/**
* The active PDO connection.
*/
private ?\PDO $pdo = null;
/**
* The database configuration.
*/
private array $config;
/**
* Create a new database connection instance.
*/
public function __construct(array $config)
{
$this->config = $config;
}
/**
* Get the PDO connection.
*/
public function getPdo(): \PDO
{
if ($this->pdo === null) {
$this->connect();
}
return $this->pdo;
}
/**
* Establish a database connection.
*/
protected function connect(): void
{
// Implementation...
}
/**
* Build the DSN string.
*/
private function buildDsn(): string
{
// Implementation...
}
}
Methoden
- Methoden SOLLTEN eine einzige Verantwortung haben (Single Responsibility Principle).
- Methoden SOLLTEN kurz sein und eine Sache gut machen.
- Methoden SOLLTEN früh zurückkehren, um die Verschachtelungstiefe zu reduzieren.
// Gut
public function getUserById(int $id): ?User
{
if ($id <= 0) {
return null;
}
return $this->userRepository->find($id);
}
// Schlecht
public function getUserById(int $id): ?User
{
if ($id > 0) {
$user = $this->userRepository->find($id);
if ($user !== null) {
return $user;
} else {
return null;
}
} else {
return null;
}
}
Typisierung
- Der Code MUSS strikte Typisierung verwenden.
- Jede Datei SOLLTE mit
declare(strict_types=1);beginnen. - Methoden und Funktionen MÜSSEN Typdeklarationen für Parameter und Rückgabewerte verwenden.
- Eigenschaften MÜSSEN Typdeklarationen verwenden.
<?php
declare(strict_types=1);
namespace App\Framework\Http;
class Request
{
private array $query;
private array $request;
public function __construct(array $query, array $request)
{
$this->query = $query;
$this->request = $request;
}
public function query(string $key, mixed $default = null): mixed
{
return $this->query[$key] ?? $default;
}
public function input(string $key, mixed $default = null): mixed
{
return $this->request[$key] ?? $default;
}
public function has(string $key): bool
{
return isset($this->request[$key]);
}
}
Dokumentation
- Alle Klassen, Methoden, Eigenschaften und Konstanten MÜSSEN mit PHPDoc-Kommentaren dokumentiert werden.
- PHPDoc-Kommentare MÜSSEN eine Beschreibung und alle relevanten Tags enthalten.
- Komplexe Codeabschnitte SOLLTEN mit Inline-Kommentaren erklärt werden.
/**
* Represents an HTTP request.
*/
class Request
{
/**
* The query parameters.
*
* @var array<string, mixed>
*/
private array $query;
/**
* Get a query parameter.
*
* @param string $key The parameter key
* @param mixed $default The default value if the parameter does not exist
*
* @return mixed The parameter value or the default value
*/
public function query(string $key, mixed $default = null): mixed
{
return $this->query[$key] ?? $default;
}
}
Fehlerbehandlung
- Exceptions SOLLTEN für außergewöhnliche Bedingungen verwendet werden.
- Benutzerdefinierte Exceptions SOLLTEN von einer Basis-Exception-Klasse erben.
- Exception-Nachrichten SOLLTEN klar und informativ sein.
// Definieren einer benutzerdefinierten Exception
class DatabaseException extends \RuntimeException
{
// ...
}
// Werfen einer Exception
if (!$this->isConnected()) {
throw new DatabaseException('Database connection failed: ' . $this->getLastError());
}
// Fangen einer Exception
try {
$user = $this->userRepository->find($id);
} catch (DatabaseException $e) {
$this->logger->error('Database error: ' . $e->getMessage());
throw new ServiceException('Could not retrieve user data', 0, $e);
}
JavaScript-Standards
Allgemeine Richtlinien
- JavaScript-Code SOLLTE ESLint mit der Konfiguration des Projekts verwenden.
- ES6+ Features SOLLTEN verwendet werden.
- Semicolons MÜSSEN verwendet werden.
Namenskonventionen
- Variablen und Funktionen MÜSSEN
camelCaseverwenden. - Klassen MÜSSEN
PascalCaseverwenden. - Konstanten MÜSSEN
UPPER_CASEmit Unterstrichen als Trennzeichen verwenden. - Private Eigenschaften und Methoden SOLLTEN mit einem Unterstrich beginnen.
// Variablen
const maxItems = 10;
let currentIndex = 0;
// Konstanten
const MAX_RETRY_COUNT = 3;
const API_BASE_URL = 'https://api.example.com';
// Funktionen
function getUserData(userId) {
// ...
}
// Klassen
class UserService {
constructor(apiClient) {
this._apiClient = apiClient;
}
async getUser(id) {
return this._apiClient.get(`/users/${id}`);
}
_handleError(error) {
console.error('API error:', error);
}
}
Codestruktur
- Jede Datei SOLLTE einen einzelnen Export haben.
- Imports SOLLTEN am Anfang der Datei stehen und nach Typ gruppiert werden.
- Funktionen SOLLTEN kurz sein und eine Sache gut machen.
// Imports
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
// Eigene Imports
import { UserService } from '../services/UserService';
import { ErrorBoundary } from '../components/ErrorBoundary';
// Komponente
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchUser = async () => {
try {
setLoading(true);
const userService = new UserService();
const userData = await userService.getUser(userId);
setUser(userData);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchUser();
}, [userId]);
if (loading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error: {error}</div>;
}
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
UserProfile.propTypes = {
userId: PropTypes.string.isRequired
};
export default UserProfile;
CSS-Standards
Allgemeine Richtlinien
- CSS-Code SOLLTE Stylelint mit der Konfiguration des Projekts verwenden.
- CSS-Präprozessoren wie SASS oder LESS KÖNNEN verwendet werden.
- CSS-Klassen SOLLTEN nach dem BEM-Muster (Block, Element, Modifier) benannt werden.
Namenskonventionen
- CSS-Klassen MÜSSEN
kebab-caseverwenden. - BEM-Notation:
.block__element--modifier
/* Block */
.user-card {
background-color: #fff;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
padding: 16px;
}
/* Element */
.user-card__avatar {
border-radius: 50%;
height: 64px;
width: 64px;
}
/* Element */
.user-card__name {
font-size: 18px;
font-weight: bold;
margin-top: 8px;
}
/* Modifier */
.user-card--premium {
background-color: #f8f8f8;
border: 1px solid #ddd;
}
Codestruktur
- CSS-Regeln SOLLTEN nach Komponenten organisiert werden.
- Medienabfragen SOLLTEN am Ende jeder Komponente stehen.
- Vendor-Präfixe SOLLTEN automatisch mit Tools wie Autoprefixer hinzugefügt werden.
/* Komponente */
.button {
background-color: #007bff;
border: none;
border-radius: 4px;
color: #fff;
cursor: pointer;
font-size: 16px;
padding: 8px 16px;
transition: background-color 0.2s;
}
.button:hover {
background-color: #0069d9;
}
.button:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);
}
.button--secondary {
background-color: #6c757d;
}
.button--secondary:hover {
background-color: #5a6268;
}
/* Medienabfragen */
@media (max-width: 768px) {
.button {
font-size: 14px;
padding: 6px 12px;
}
}
Tools und Automatisierung
Code-Linting
Das Projekt verwendet verschiedene Linting-Tools, um die Einhaltung der Coding Standards zu gewährleisten:
- PHP_CodeSniffer für PHP
- ESLint für JavaScript
- Stylelint für CSS
Automatische Formatierung
Das Projekt unterstützt automatische Codeformatierung mit:
- PHP-CS-Fixer für PHP
- Prettier für JavaScript und CSS
Verwendung der Tools
PHP_CodeSniffer
# Überprüfen des Codes
vendor/bin/phpcs src tests
# Automatisches Beheben von Problemen
vendor/bin/phpcbf src tests
PHP-CS-Fixer
# Überprüfen des Codes
vendor/bin/php-cs-fixer fix --dry-run --diff src
# Automatisches Beheben von Problemen
vendor/bin/php-cs-fixer fix src
ESLint
# Überprüfen des Codes
npm run lint:js
# Automatisches Beheben von Problemen
npm run lint:js:fix
Stylelint
# Überprüfen des Codes
npm run lint:css
# Automatisches Beheben von Problemen
npm run lint:css:fix
Prettier
# Formatieren von JavaScript und CSS
npm run format
Weitere Informationen
- Pull Request-Anleitung: Erfahren Sie, wie Sie Pull Requests erstellen und überprüfen.
- Dokumentations-Anleitung: Erfahren Sie, wie Sie zur Dokumentation beitragen können.
- Architekturübersicht: Überblick über die Architektur des Frameworks.