在Laravel项目开发过程中,字符串长度标准化是常见需求,比如生成的订单号需要固定为16位,不足的部分用0填充,或者用户编号需要固定为10位,不足用空格填充。使用Eloquent的Attribute Padding属性填充机制,可以在模型层面统一处理这类逻辑,避免重复的字符串处理代码。

什么是Eloquent Attribute Padding
Eloquent Attribute Padding指的是在Eloquent模型中,对指定属性进行长度填充处理的逻辑,通常结合访问器(Accessor)和修改器(Mutator)实现。访问器用于在读取属性时处理数据,修改器用于在写入属性时处理数据,两者配合就能实现字符串长度的标准化。
基础实现步骤
1. 定义填充规则
首先需要在模型中定义需要填充的属性、目标长度、填充字符和填充方向。我们可以在模型中定义几个常量来保存这些配置,方便后续维护。
<?php
namespace AppModels;
use IlluminateDatabaseEloquentModel;
class Order extends Model
{
// 需要填充的属性名
const PADDING_ATTRIBUTES = ['order_no', 'user_code'];
// 目标长度
const PADDING_LENGTH = 16;
// 填充字符
const PADDING_CHAR = '0';
// 填充方向:STR_PAD_LEFT 左填充,STR_PAD_RIGHT 右填充,STR_PAD_BOTH 两端填充
const PADDING_DIRECTION = STR_PAD_LEFT;
}
2. 实现修改器处理写入逻辑
修改器会在模型属性被赋值时触发,我们可以在这里对字符串进行填充处理,确保存入数据库的数据已经是标准化长度。
<?php
namespace AppModels;
use IlluminateDatabaseEloquentModel;
class Order extends Model
{
// 省略上面的常量定义
/**
* 设置订单号的修改器
* @param $value
*/
public function setOrderNoAttribute($value)
{
// 如果值长度不足,进行填充
if (strlen($value) < self::PADDING_LENGTH) {
$this->attributes['order_no'] = str_pad($value, self::PADDING_LENGTH, self::PADDING_CHAR, self::PADDING_DIRECTION);
} else {
$this->attributes['order_no'] = $value;
}
}
/**
* 设置用户编号的修改器
* @param $value
*/
public function setUserCodeAttribute($value)
{
if (strlen($value) < self::PADDING_LENGTH) {
$this->attributes['user_code'] = str_pad($value, self::PADDING_LENGTH, self::PADDING_CHAR, self::PADDING_DIRECTION);
} else {
$this->attributes['user_code'] = $value;
}
}
}
3. 实现访问器处理读取逻辑
如果数据库中已经存在未标准化的旧数据,或者需要在读取时统一处理格式,可以添加访问器。访问器会在获取属性值时触发。
<?php
namespace AppModels;
use IlluminateDatabaseEloquentModel;
class Order extends Model
{
// 省略上面的常量和修改器定义
/**
* 获取订单号的访问器
* @param $value
* @return string
*/
public function getOrderNoAttribute($value)
{
if (strlen($value) < self::PADDING_LENGTH) {
return str_pad($value, self::PADDING_LENGTH, self::PADDING_CHAR, self::PADDING_DIRECTION);
}
return $value;
}
/**
* 获取用户编号的访问器
* @param $value
* @return string
*/
public function getUserCodeAttribute($value)
{
if (strlen($value) < self::PADDING_LENGTH) {
return str_pad($value, self::PADDING_LENGTH, self::PADDING_CHAR, self::PADDING_DIRECTION);
}
return $value;
}
}
通用化封装方案
如果多个属性都需要相同的填充规则,重复写修改器和访问器会很冗余,我们可以封装一个通用的方法来处理。
<?php
namespace AppModels;
use IlluminateDatabaseEloquentModel;
class Order extends Model
{
const PADDING_ATTRIBUTES = ['order_no', 'user_code'];
const PADDING_LENGTH = 16;
const PADDING_CHAR = '0';
const PADDING_DIRECTION = STR_PAD_LEFT;
/**
* 通用的属性填充处理方法
* @param $value
* @return string
*/
protected function padAttribute($value)
{
if (strlen($value) < self::PADDING_LENGTH) {
return str_pad($value, self::PADDING_LENGTH, self::PADDING_CHAR, self::PADDING_DIRECTION);
}
return $value;
}
// 动态生成修改器和访问器
public function __call($method, $parameters)
{
// 处理修改器:setXxxAttribute
if (preg_match('/^set(w+)Attribute$/', $method, $matches)) {
$attribute = snake_case($matches[1]);
if (in_array($attribute, self::PADDING_ATTRIBUTES)) {
$value = $parameters[0];
$this->attributes[$attribute] = $this->padAttribute($value);
return;
}
}
// 处理访问器:getXxxAttribute
if (preg_match('/^get(w+)Attribute$/', $method, $matches)) {
$attribute = snake_case($matches[1]);
if (in_array($attribute, self::PADDING_ATTRIBUTES)) {
$value = $this->attributes[$attribute] ?? null;
return $value ? $this->padAttribute($value) : null;
}
}
return parent::__call($method, $parameters);
}
}
使用示例
完成模型定义后,就可以直接使用填充功能了,不需要手动调用str_pad函数。
<?php // 创建订单时,自动填充order_no到16位 $order = new AppModelsOrder(); $order->order_no = '12345'; // 实际会保存为0000000000012345 $order->user_code = 'abc'; // 实际会保存为0000000000000abc $order->save(); // 读取时也会自动处理未标准化的旧数据 $order = AppModelsOrder::find(1); echo $order->order_no; // 输出16位标准化的订单号
注意事项
- 填充字符如果是多字节字符(比如中文),需要使用mb_strlen计算长度,str_pad函数默认处理单字节字符,多字节场景需要调整逻辑。
- 如果数据库字段长度小于填充后的目标长度,会导致数据截断,需要提前确认数据库字段的长度设置。
- 如果不需要在读取时处理旧数据,可以只定义修改器,不需要定义访问器,减少不必要的性能消耗。
- 填充方向可以根据需求调整,比如订单号通常用左填充0,而某些显示场景可能需要右填充空格。
PHPEloquent_Attribute_PaddingLaravel字符串长度标准化修改时间:2026-07-09 07:45:30