andydefer/php-services 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

andydefer/php-services

最新稳定版本:v0.3.6

Composer 安装命令:

composer require andydefer/php-services

包简介

Collection of reusable services for PHP and Laravel applications including model transformation, caching, and common business logic

README 文档

README

PHP Version Laravel Version License

Installation

composer require andydefer/php-services

Philosophie du package

Ce package est une collection de services réutilisables pour PHP et Laravel.

Il s'inspire de plusieurs principes du génie logiciel qui servent de boussole, pas de carcan :

Principe Ce qu'il encourage Ce qu'il n'impose pas
Composition Over Inheritance Préférer l'injection de dépendances à l'héritage L'héritage reste possible quand il est pertinent
Dependency Inversion Dépendre des interfaces plutôt que des classes concrètes Les DTOs et Value Objects peuvent être concrets
Capability-Based Design Exposer des capacités spécifiques plutôt que des services fourre-tout Un service peut avoir plusieurs méthodes cohésives
Domain-Driven Design Organiser le code par domaine fonctionnel La structure peut évoluer librement

L'objectif est d'obtenir un code testable, découplé et maintenable, sans tomber dans l'extrémisme architectural.

Ce qu'un Service est

// ✅ Un service = un conteneur de méthodes qui partagent un même domaine
class OrderCalculatorService
{
    // ✅ Des dépendances injectées dans le constructeur
    public function __construct(
        private readonly TaxService $taxService,
        private readonly OrderConfig $config,
    ) {}
    
    // ✅ Des méthodes qui reçoivent leurs données en paramètres
    public function calculateTotal(OrderRecord $order): float
    {
        $subtotal = $this->calculateSubtotal($order);
        $tax = $this->taxService->calculate($subtotal);
        
        return $subtotal + $tax;
    }
    
    // ✅ Pas d'état interne, pas de mémoire entre les appels
    private function calculateSubtotal(OrderRecord $order): float
    {
        return array_reduce($order->items, fn($c, $i) => $c + ($i->price * $i->quantity), 0);
    }
}

Pourquoi cette philosophie ?

Problème : Les traits (anti-pattern)

// ❌ Un trait : impossible à tester isolément
trait FileCreator
{
    private Filesystem $files;
    
    public function createFile(string $path, string $content): bool
    {
        $this->files = new Filesystem();  // Dépendance cachée
        return $this->files->put($path, $content);
    }
}

class TaskDirective extends AbstractDirective
{
    use FileCreator;  // ❌ Couplage implicite, test impossible
}

Solution : Le service

// ✅ Un service : testable, injectable, découplé
class FileCreatorService
{
    public function __construct(
        private readonly Filesystem $files,  // ✅ Injection explicite
    ) {}
    
    public function createFile(string $path, string $content): bool
    {
        return $this->files->put($path, $content);
    }
}

class TaskDirective extends AbstractDirective
{
    public function __construct(
        private readonly FileCreatorService $fileCreator,  // ✅ Dépendance claire
    ) {}
}

Exemple complet : La testabilité en action

// Le service
class UserService
{
    public function __construct(
        private readonly UserRepository $repository,
        private readonly LoggerInterface $logger,
    ) {}
    
    public function findActiveUser(int $id): ?User
    {
        $this->logger->info('Searching for active user', ['id' => $id]);
        
        $user = $this->repository->findActive($id);
        
        if (!$user) {
            $this->logger->warning('Active user not found', ['id' => $id]);
            return null;
        }
        
        return $user;
    }
}

// Le test
class UserServiceTest extends TestCase
{
    public function test_findActiveUser_returns_user_when_exists(): void
    {
        // ✅ Toutes les dépendances sont mockables
        $repository = $this->createMock(UserRepository::class);
        $repository->method('findActive')->willReturn($user);
        
        $logger = $this->createMock(LoggerInterface::class);
        $logger->expects($this->once())->method('info');
        
        $service = new UserService($repository, $logger);
        $result = $service->findActiveUser(1);
        
        $this->assertSame($user, $result);
        
        // ✅ Aucune base de données réelle
        // ✅ Aucun fichier log réel
        // ✅ Test rapide, isolé, fiable
    }
}

Quand déroger aux principes ?

La philosophie de ce package est pragmatique :

Règle Peut-on déroger ? Exemple
Pas d'état interne ⚠️ Exception rare Cache interne avec TTL court
Pas de final ✅ Oui Classe utilitaire sans dépendances
Dépendre des interfaces ✅ Oui Value Objects, DTOs, Configs
Une capacité par service ✅ Oui OrderCalculatorService a 5 méthodes liées

Le critère ultime : Est-ce que mon code reste testable ?

Services disponibles

Service Description
ModelTransformableService Convertit les modèles Eloquent en Data DTOs typés

Voir la documentation complète

License

MIT © Andy Defer

统计信息

  • 总下载量: 6
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 2
  • 依赖项目数: 1
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-06-06

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固