本文目录导读:

我来提供一个完整的PHP服务层代码示例,包含常见的业务场景和最佳实践。
基础服务层架构
<?php
// app/Services/BaseService.php
namespace App\Services;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Collection;
use Exception;
abstract class BaseService
{
protected Model $model;
/**
* 创建记录
*/
public function create(array $data): Model
{
try {
DB::beginTransaction();
$result = $this->model->create($data);
DB::commit();
return $result;
} catch (Exception $e) {
DB::rollBack();
Log::error('创建失败: ' . $e->getMessage(), $data);
throw new \RuntimeException('创建记录失败');
}
}
/**
* 更新记录
*/
public function update(int $id, array $data): Model
{
try {
DB::beginTransaction();
$model = $this->model->findOrFail($id);
$model->update($data);
DB::commit();
return $model->fresh();
} catch (Exception $e) {
DB::rollBack();
Log::error('更新失败: ' . $e->getMessage(), ['id' => $id]);
throw new \RuntimeException('更新记录失败');
}
}
/**
* 删除记录
*/
public function delete(int $id): bool
{
try {
DB::beginTransaction();
$model = $this->model->findOrFail($id);
$result = $model->delete();
DB::commit();
return $result;
} catch (Exception $e) {
DB::rollBack();
Log::error('删除失败: ' . $e->getMessage(), ['id' => $id]);
throw new \RuntimeException('删除记录失败');
}
}
/**
* 获取记录
*/
public function find(int $id): Model
{
return $this->model->findOrFail($id);
}
/**
* 获取所有记录
*/
public function all(): Collection
{
return $this->model->all();
}
}
用户服务示例
<?php
// app/Services/UserService.php
namespace App\Services;
use App\Models\User;
use App\Repositories\UserRepository;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
class UserService extends BaseService
{
protected UserRepository $userRepository;
public function __construct(UserRepository $userRepository)
{
parent::__construct();
$this->model = new User();
$this->userRepository = $userRepository;
}
/**
* 创建用户(带验证和业务逻辑)
*/
public function createUser(array $data): User
{
// 业务验证
$validator = Validator::make($data, [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8|confirmed',
'role' => 'required|in:admin,user,editor'
]);
if ($validator->fails()) {
throw new ValidationException($validator);
}
// 业务逻辑处理
$data['password'] = Hash::make($data['password']);
$data['status'] = 'active';
$data['verification_token'] = $this->generateVerificationToken();
// 调用父类创建
$user = parent::create($data);
// 发送欢迎邮件
$this->sendWelcomeEmail($user);
return $user;
}
/**
* 更新用户资料
*/
public function updateProfile(int $userId, array $data): User
{
$allowedFields = ['name', 'avatar', 'bio', 'phone'];
$filteredData = array_intersect_key($data, array_flip($allowedFields));
return parent::update($userId, $filteredData);
}
/**
* 更改用户密码
*/
public function changePassword(int $userId, string $oldPassword, string $newPassword): bool
{
$user = $this->find($userId);
// 验证旧密码
if (!Hash::check($oldPassword, $user->password)) {
throw new \InvalidArgumentException('原密码错误');
}
// 更新密码
return parent::update($userId, [
'password' => Hash::make($newPassword)
]) instanceof User;
}
/**
* 获取用户列表(带分页和缓存)
*/
public function getUserList(array $filters = [], int $perPage = 20): \Illuminate\Pagination\LengthAwarePaginator
{
$cacheKey = 'users_list_' . md5(serialize($filters)) . '_' . $perPage;
return Cache::remember($cacheKey, 3600, function () use ($filters, $perPage) {
$query = $this->model->newQuery();
if (isset($filters['status'])) {
$query->where('status', $filters['status']);
}
if (isset($filters['search'])) {
$query->where(function ($q) use ($filters) {
$q->where('name', 'like', '%' . $filters['search'] . '%')
->orWhere('email', 'like', '%' . $filters['search'] . '%');
});
}
$query->orderBy($filters['sort_by'] ?? 'created_at', $filters['sort_order'] ?? 'desc');
return $query->paginate($perPage);
});
}
/**
* 获取用户统计信息
*/
public function getUserStats(int $userId): array
{
$user = $this->find($userId);
return [
'total_orders' => $user->orders()->count(),
'total_spent' => $user->orders()->sum('total_amount'),
'recent_orders' => $user->orders()->latest()->take(5)->get(),
'favorite_products' => $user->favorites()->latest()->take(10)->get()
];
}
/**
* 软删除用户
*/
public function softDeleteUser(int $userId): bool
{
$user = $this->find($userId);
// 撤销token
$user->tokens()->delete();
// 更新状态
$user->status = 'deleted';
$user->save();
// 异步清理用户数据
$this->cleanupUserData($userId);
return parent::delete($userId);
}
/**
* 导出用户数据(GDPR合规)
*/
public function exportUserData(int $userId): array
{
$user = $this->find($userId);
return [
'profile' => $user->toArray(),
'orders' => $user->orders()->get()->toArray(),
'addresses' => $user->addresses()->get()->toArray(),
'payment_methods' => $user->paymentMethods()->get()->toArray()
];
}
/**
* 批量操作
*/
public function batchUpdateStatus(array $userIds, string $status): int
{
$affected = 0;
try {
DB::beginTransaction();
$affected = $this->model->whereIn('id', $userIds)
->where('status', '!=', $status)
->update(['status' => $status]);
DB::commit();
return $affected;
} catch (Exception $e) {
DB::rollBack();
throw $e;
}
}
// 私有辅助方法
private function generateVerificationToken(): string
{
return bin2hex(random_bytes(32));
}
private function sendWelcomeEmail(User $user): void
{
Log::info('发送欢迎邮件', ['user_id' => $user->id]);
// 邮件发送逻辑
}
private function cleanupUserData(int $userId): void
{
// 清理用户数据的异步任务
}
}
订单服务示例(更复杂的业务逻辑)
<?php
// app/Services/OrderService.php
namespace App\Services;
use App\Models\Order;
use App\Models\OrderItem;
use App\Models\Product;
use App\Models\InventoryLog;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Lock;
use Illuminate\Support\Facades\Log;
class OrderService extends BaseService
{
public function __construct()
{
$this->model = new Order();
}
/**
* 创建订单(并发控制)
*/
public function createOrder(int $userId, array $items, array $options = []): Order
{
$lockKey = 'order_creation_' . $userId;
// 使用分布式锁防止并发创建
return Lock::lock($lockKey, 10, function () use ($userId, $items, $options) {
try {
DB::beginTransaction();
// 创建订单
$order = $this->model->create([
'user_id' => $userId,
'order_number' => $this->generateOrderNumber(),
'status' => 'pending',
'total_amount' => 0,
'shipping_address' => $options['shipping_address'] ?? null,
'billing_address' => $options['billing_address'] ?? null,
'payment_method' => $options['payment_method'] ?? null,
'notes' => $options['notes'] ?? null
]);
$totalAmount = 0;
$orderItems = [];
// 处理每个商品
foreach ($items as $item) {
$product = Product::where('id', $item['product_id'])
->where('status', 'active')
->lockForUpdate()
->firstOrFail();
// 检查库存
if ($product->stock < $item['quantity']) {
throw new \RuntimeException('商品库存不足: ' . $product->name);
}
// 计算价格(考虑促销)
$unitPrice = $this->calculatePrice($product, $item['quantity'], $options);
// 创建订单项
$orderItems[] = [
'product_id' => $product->id,
'product_name' => $product->name,
'product_sku' => $product->sku,
'quantity' => $item['quantity'],
'unit_price' => $unitPrice,
'subtotal' => $unitPrice * $item['quantity']
];
$totalAmount += $unitPrice * $item['quantity'];
// 扣减库存
$product->update([
'stock' => $product->stock - $item['quantity']
]);
// 记录库存流水
InventoryLog::create([
'product_id' => $product->id,
'type' => 'order',
'quantity' => -$item['quantity'],
'reference_id' => $order->id,
'reference_type' => 'order',
'remarks' => "订单 #{$order->order_number}"
]);
}
// 应用优惠券
$discount = $this->applyCoupon($totalAmount, $options['coupon'] ?? null);
// 计算运费
$shippingFee = $this->calculateShippingFee($totalAmount, $options);
// 计算税费
$tax = $this->calculateTax($totalAmount);
// 更新订单
$order->items()->createMany($orderItems);
$order->update([
'total_amount' => $totalAmount,
'discount_amount' => $order['discount'] ?? 0,
'shipping_fee' => $shippingFee,
'tax_amount' => $tax,
'grand_total' => $totalAmount - ($discount ?? 0) + $shippingFee + $tax,
'promo_code' => $options['coupon'] ?? null
]);
// 触发事件
Event::dispatch('order.created', ['order' => $order]);
DB::commit();
// 异步任务
$this->afterOrderCreated($order);
return $order->fresh(['items', 'user']);
} catch (\Exception $e) {
DB::rollBack();
Log::error('创建订单失败', [
'user_id' => $userId,
'items' => $items,
'error' => $e->getMessage()
]);
throw $e;
}
});
}
/**
* 取消订单
*/
public function cancelOrder(int $orderId, string $reason = ''): Order
{
try {
DB::beginTransaction();
$order = $this->model->findOrFail($orderId);
// 检查是否可取消
if (!in_array($order->status, ['pending', 'processing'])) {
throw new \RuntimeException('当前订单状态不能取消');
}
// 更新状态
$order->update([
'status' => 'cancelled',
'cancel_reason' => $reason,
'cancelled_at' => now()
]);
// 恢复库存
foreach ($order->items as $item) {
$item->product->increment('stock', $item->quantity);
InventoryLog::create([
'product_id' => $item->product_id,
'type' => 'order_cancel',
'quantity' => $item->quantity,
'reference_id' => $order->id,
'reference_type' => 'order',
'remarks' => "订单取消 #{$order->order_number}"
]);
}
// 退款处理
if ($order->payment_status === 'paid') {
$this->processRefund($order);
}
DB::commit();
return $order->fresh();
} catch (\Exception $e) {
DB::rollBack();
throw $e;
}
}
/**
* 订单状态流转
*/
public function transitionOrderStatus(Order $order, string $newStatus): bool
{
$transitions = [
'pending' => ['processing', 'cancelled'],
'processing' => ['shipped', 'cancelled'],
'shipped' => ['delivered'],
'delivered' => ['completed'],
'cancelled' => [],
'completed' => []
];
if (!in_array($newStatus, $transitions[$order->status] ?? [])) {
throw new \InvalidArgumentException(
"无效的状态转换: {$order->status} -> {$newStatus}"
);
}
$order->update([
'status' => $newStatus,
'status_history' => array_merge(
$order->status_history ?? [],
[
[
'from' => $order->status,
'to' => $newStatus,
'at' => now()->toDateTimeString()
]
]
)
]);
return true;
}
/**
* 获取订单报表
*/
public function getOrderReport(array $filters = []): array
{
$query = $this->model->newQuery();
// 时间过滤
if (isset($filters['from']) && isset($filters['to'])) {
$query->whereBetween('created_at', [$filters['from'], $filters['to']]);
}
// 状态过滤
if (isset($filters['status'])) {
$query->where('status', $filters['status']);
}
$stats = [
'total_orders' => $query->count(),
'total_revenue' => $query->sum('grand_total'),
'avg_order_value' => $query->avg('grand_total'),
'status_breakdown' => $query->groupBy('status')
->selectRaw('status, COUNT(*) as count, SUM(grand_total) as total')
->get()
->pluck('total', 'status')
];
// 每日订单统计
$dailyStats = $this->model->newQuery()
->whereBetween('created_at', [$filters['from'] ?? now()->subDays(30), $filters['to'] ?? now()])
->groupBy('date')
->selectRaw('DATE(created_at) as date, COUNT(*) as orders, SUM(grand_total) as revenue')
->get();
return [
'summary' => $stats,
'daily_breakdown' => $dailyStats,
'top_products' => $this->getTopProducts($filters['from'] ?? null, $filters['to'] ?? null)
];
}
// 辅助私有方法
private function generateOrderNumber(): string
{
return 'ORD-' . date('YmdHis') . '-' . strtoupper(substr(uniqid(), -6));
}
private function calculatePrice(Product $product, int $quantity, array $options): float
{
$price = $product->price;
// 促销价
if ($product->sale_price && $product->sale_price < $price) {
$price = $product->sale_price;
}
// 批量折扣示例
if ($quantity >= 10) {
$price *= 0.9; // 10% discount
}
// 会员价
if (isset($options['user']) && $options['user']->vip_level > 0) {
$price *= (1 - $options['user']->vip_discount);
}
return round($price, 2);
}
private function applyCoupon(float $amount, ?string $couponCode): float
{
// 优惠券逻辑(略)
return 0;
}
private function calculateShippingFee(float $totalAmount, array $options): float
{
return $totalAmount > 50 ? 0 : 5.99;
}
private function calculateTax(float $amount): float
{
return $amount * 0.08;
}
private function processRefund(Order $order): void
{
// 退款处理逻辑
}
private function afterOrderCreated(Order $order): void
{
// 发送邮件通知
// 生成发票
// 通知库存系统
}
private function getTopProducts(?string $from, ?string $to): \Illuminate\Support\Collection
{
return OrderItem::query()
->join('orders', 'orders.id', '=', 'order_items.order_id')
->when($from, fn($q) => $q->where('orders.created_at', '>=', $from))
->when($to, fn($q) => $q->where('orders.created_at', '<=', $to))
->where('orders.status', '!=', 'cancelled')
->groupBy('product_id', 'product_name')
->selectRaw('product_id, product_name, SUM(quantity) as total_quantity, SUM(subtotal) as total_amount')
->orderByDesc('total_quantity')
->limit(10)
->get();
}
}
服务提供者注册示例
<?php
// app/Providers/AppServiceProvider.php
namespace App\Providers;
use App\Services\UserService;
use App\Services\OrderService;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
// 绑定服务
$this->app->singleton(UserService::class, function ($app) {
return new UserService(
$app->make('App\Repositories\UserRepository')
);
});
$this->app->singleton(OrderService::class, function ($app) {
return new OrderService();
});
// 也可以简单的绑定
$this->app->bind(UserService::class);
$this->app->bind(OrderService::class);
}
public function boot(): void
{
//
}
}
控制器中使用服务层
<?php
// app/Http/Controllers/OrderController.php
namespace App\Http\Controllers;
use App\Services\OrderService;
use App\Services\UserService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class OrderController extends Controller
{
protected OrderService $orderService;
protected UserService $userService;
public function __construct(OrderService $orderService, UserService $userService)
{
$this->orderService = $orderService;
$this->userService = $userService;
$this->middleware('auth:api');
}
/**
* 创建订单
*/
public function store(Request $request)
{
// 验证请求
$validator = Validator::make($request->all(), [
'items' => 'required|array|min:1',
'items.*.product_id' => 'required|exists:products,id',
'items.*.quantity' => 'required|integer|min:1',
'shipping_address' => 'required|array',
'payment_method' => 'required|string'
]);
if ($validator->fails()) {
return response()->json(['errors' => $validator->errors()], 422);
}
try {
// 调用服务层
$order = $this->orderService->createOrder(
$request->user()->id,
$request->items,
[
'shipping_address' => $request->shipping_address,
'payment_method' => $request->payment_method,
'coupon' => $request->coupon_code
]
);
return response()->json([
'message' => '订单创建成功',
'data' => $order
], 201);
} catch (\Exception $e) {
return response()->json([
'message' => $e->getMessage()
], 500);
}
}
/**
* 订单列表
*/
public function index(Request $request)
{
$filters = $request->only(['status', 'from', 'to', 'page', 'per_page']);
$orders = $this->orderService->getOrderReport($filters);
return response()->json([
'data' => $orders
]);
}
}
单元测试示例
<?php
// tests/Feature/OrderServiceTest.php
namespace Tests\Feature;
use App\Models\Order;
use App\Models\Product;
use App\Models\User;
use App\Services\OrderService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class OrderServiceTest extends TestCase
{
use RefreshDatabase;
protected OrderService $orderService;
protected function setUp(): void
{
parent::setUp();
$this->orderService = app(OrderService::class);
}
/** @test */
public function it_creates_an_order_successfully()
{
$user = User::factory()->create();
$product = Product::factory()->create(['stock' => 10, 'price' => 99.99]);
$order = $this->orderService->createOrder($user->id, [
['product_id' => $product->id, 'quantity' => 2]
]);
$this->assertInstanceOf(Order::class, $order);
$this->assertEquals($order->total_amount, 199.98);
$this->assertEquals($order->status, 'pending');
$this->assertEquals($product->fresh()->stock, 8);
}
/** @test */
public function it_throws_exception_when_stock_insufficient()
{
$user = User::factory()->create();
$product = Product::factory()->create(['stock' => 5]);
$this->expectException(\RuntimeException::class);
$this->orderService->createOrder($user->id, [
['product_id' => $product->id, 'quantity' => 10]
]);
}
/** @test */
public function it_cancels_order_and_restores_stock()
{
$user = User::factory()->create();
$product = Product::factory()->create(['stock' => 10]);
$order = $this->orderService->createOrder($user->id, [
['product_id' => $product->id, 'quantity' => 3]
]);
$this->orderService->cancelOrder($order->id);
$this->assertEquals($order->fresh()->status, 'cancelled');
$this->assertEquals($product->fresh()->stock, 10);
}
}
服务层设计最佳实践
分层原则
- Controller:只负责请求响应流程
- Service:业务逻辑核心
- Repository:数据访问层(可选)
- Model:数据实体和关联
事务管理
- 所有写操作放入事务
- 使用锁处理并发问题
- 失败时正确回滚
异常处理
- 自定义异常类型
- 统一异常处理
- 日志记录
依赖注入
- 服务通过构造函数注入
- 避免硬编码依赖
- 便于单元测试
缓存策略
- 查询结果缓存
- 缓存失效时机合理
- 缓存键设计规范
性能优化
- 批量操作
- 预加载关系
- 查询优化
安全考虑
- 权限检查
- 数据验证
- 防止注入
可维护性
- 单一职责
- 清晰命名
- 注释记录
- 单元测试
服务层是业务逻辑的核心,设计良好的服务层能提高代码复用性、可测试性和可维护性,根据项目复杂度,可以适当简化或扩展服务层结构。