Skip to content

Commit e795588

Browse files
committed
[feat] ArrayOf
1.新增 ArrayOf 對 Enum 的支援
1 parent 0e74387 commit e795588

File tree

2 files changed

+53
-14
lines changed

2 files changed

+53
-14
lines changed

CHANGELOG.md

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# CHANGELOG
22

3+
## [v2.4.0] - 2025-09-01
4+
5+
### 🎉 新功能
6+
7+
- `#[ArrayOf]` 現在支援 Enum 類型:可傳入 enum case 名稱或其底層 scalar 值,自動解析為對應 case。
8+
9+
---
10+
311
## [v2.3.2] - 2025-08-31
412

513
- **修正 UnionType 未嘗試所有型別就直接拋錯的問題**
@@ -11,12 +19,14 @@
1119
## [v2.3.0] - 2025-08-07
1220

1321
### 🎉 新功能
22+
1423
- **強化 `#[ArrayOf]` 標註驗證**
1524
- 新增類型檢查,確保指定的類別是 ImmutableBase 的子類
1625
- 支援傳入已實例化的物件或陣列資料
1726
- 優化錯誤訊息提供更清楚的指引
1827

1928
### ✨ 功能改進
29+
2030
- **增強 `toArray()` 方法**
2131
- 優化陣列處理邏輯,支援物件陣列的遞迴序列化
2232
- 自動處理 ArrayOf 標註的物件陣列輸出
@@ -25,17 +35,20 @@
2535
- 更嚴格的屬性可見性檢查
2636

2737
### 🗑️ 正式移除
38+
2839
- **移除已棄用標註**
2940
- `#[Relaxed]` - 已完全移除
3041
- `#[Expose]` - 已完全移除
3142
- `#[Reason]` - 已完全移除
3243

3344
### 🔧 重大變更
45+
3446
- **Breaking Change**: 所有子類現在必須使用架構模式標註
3547
- **Breaking Change**: ValueObject 和 Entity 新增支援 protected 屬性
3648
- **Breaking Change**: 移除所有舊版標註
3749

3850
### 📚 範例
51+
3952
```php
4053
#[DataTransferObject]
4154
class OrderDTO extends ImmutableBase
@@ -56,18 +69,21 @@ $order = new OrderDTO([
5669
## [v2.2.0] - 2025-08-01
5770

5871
### 🎉 新功能
72+
5973
- **新增 `#[ArrayOf]` 標註**
6074
- 支援陣列屬性的自動實例化
6175
- 可指定陣列元素的類別類型
6276
- 自動將陣列數據轉換為指定類別的實例
6377
- 提供錯誤驗證,確保類別名稱不為空
6478

6579
### 📝 更新
80+
6681
- **調整廢棄時程**
6782
- `#[Relaxed]` - 廢棄時程延後至 v2.3.0
6883
- `#[Expose]` - 廢棄時程延後至 v2.3.0
6984

7085
### 📚 範例
86+
7187
```php
7288
#[DataTransferObject]
7389
class UserListDTO extends ImmutableBase
@@ -91,12 +107,14 @@ $userList = new UserListDTO([
91107
## [v2.1.0] - 2025-08-01
92108

93109
### 🎉 新功能
110+
94111
- **新增架構模式標註**
95112
- `#[DataTransferObject]` - 資料傳輸物件,要求所有屬性為 public readonly
96113
- `#[ValueObject]` - 值物件,要求所有屬性為 private
97114
- `#[Entity]` - 實體物件,要求所有屬性為 private
98115

99116
### ✨ 功能改進
117+
100118
- **增強屬性訪問控制**
101119
- 根據架構模式自動驗證屬性可見性
102120
- DataTransferObject 強制 public readonly 屬性
@@ -106,10 +124,12 @@ $userList = new UserListDTO([
106124
- 改進型別驗證錯誤訊息
107125

108126
### 🗑️ 即將棄用標註
127+
109128
- `#[Relaxed]` - 標記為 @deprecated v2.3.0
110129
- `#[Expose]` - 標記為 @deprecated v2.3.0
111130

112131
### 📚 範例
132+
113133
```php
114134
// DataTransferObject 模式
115135
#[DataTransferObject]
@@ -119,7 +139,7 @@ class UserDto extends ImmutableBase
119139
public readonly int $age;
120140
}
121141

122-
// ValueObject 模式
142+
// ValueObject 模式
123143
#[ValueObject]
124144
class Money extends ImmutableBase
125145
{
@@ -128,7 +148,7 @@ class Money extends ImmutableBase
128148
}
129149

130150
// Entity 模式
131-
#[Entity]
151+
#[Entity]
132152
class User extends ImmutableBase
133153
{
134154
private string $id;
@@ -141,29 +161,34 @@ class User extends ImmutableBase
141161
## [v2.0.0] - 2025-07-20
142162

143163
### 🎉 新功能
164+
144165
- **新增屬性標註系統**
145166
- `#[Relaxed]` - 鬆散模式,不強制要求填寫 `#[Reason]`
146167
- `#[Expose]` - 標記可被 `toArray()` 輸出的屬性
147168
- `#[Reason]` - 屬性非 private 時強制使用此標註說明設計原因
148169

149170
### ✨ 功能改進
171+
150172
- **優化 `with()` 方法**
151173
- 現已支援嵌套 ImmutableBase 物件的部分更新
152174
- 使用 Reflection 直接處理屬性,不再依賴 `toArray()`
153175
- 支援對嵌套物件進行遞迴 `with()` 操作
154176

155177
### 🔧 重構
178+
156179
- **屬性管理強化**
157180
- 移除 `$lock` 屬性和 `HIDDEN` 常數機制
158181
- 新增屬性訪問控制檢查(禁止非 readonly 的 public 屬性)
159182
- 新增 `isRelaxed()` 方法檢查類別是否為鬆散模式
160183

161184
### 🔄 API 變更
185+
162186
- **`with()` 方法**:現在支援嵌套物件的部分更新
163187
- **`toArray()` 方法**:移除 `$lock` 檢查,簡化邏輯
164188
- **屬性管理**:引入新的屬性標註系統取代舊的隱藏機制
165189

166190
### 📚 範例
191+
167192
```php
168193
// 現在支援嵌套更新
169194
$user = $user->with([
@@ -178,19 +203,25 @@ $user = $user->with([
178203
---
179204

180205
## [v1.1.0] - 之前版本
206+
181207
- 實現 `toArray()` 功能
182208

183-
## [v1.04] - 之前版本
209+
## [v1.04] - 之前版本
210+
184211
- 修復 `toArray()` 相關問題
185212

186213
## [v1.0.3] - 之前版本
214+
187215
- 重構建構子
188216

189217
## [v1.0.2] - 之前版本
218+
190219
- 重構建構子、備註和 `toArray()`
191220

192221
## [v1.0.1] - 之前版本
222+
193223
- 重構 namespace
194224

195225
## [v1.0.0] - 之前版本
196-
- 初始版本
226+
227+
- 初始版本

src/ImmutableBase.php

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,26 +71,34 @@ public function __construct(array $data = [])
7171
$nullable = $type->allowsNull();
7272
$hasDefault = $property->hasDefaultValue();
7373
$arrayOf = $property->getAttributes(ArrayOf::class);
74-
$class = null;
74+
$arg = null;
7575
if ($arrayOf) {
7676
if ($arrayOf[0]->newInstance()->error) {
7777
throw new Exception('ArrayOf class 不能為空');
7878
}
79-
$class = $arrayOf[0]->getArguments()[0];
80-
if (!is_subclass_of($class, self::class)) {
79+
$arg = $arrayOf[0]->getArguments()[0];
80+
if (!enum_exists($arg) && !is_subclass_of($arg, self::class)) {
8181
throw new Exception('ArrayOf 指定的 class 必須為 ImmutableBase 的子類');
8282
}
8383
}
8484
$value = match(true) {
8585
!$exists && !$nullable => throw new Exception("必須傳入 $type"),
86-
$arrayOf && $class => array_map(function ($item) use ($class) {
87-
if (is_array($item)) {
88-
return new $class($item);
89-
} elseif ($item instanceof $class) {
90-
return $item;
91-
} else {
92-
throw new Exception("必須傳入 array 或 $class 實例");
86+
$arrayOf && $arg => array_map(function ($item) use ($arg) {
87+
$case = null;
88+
if (enum_exists($arg)) {
89+
$names = array_column($arg::cases(), 'name');
90+
if (in_array($item, $names)) {
91+
$case = $arg::{$item};
92+
} elseif (is_int($item) || is_string($item)) {
93+
$case = $arg::tryFrom($item);
94+
}
9395
}
96+
return match(true) {
97+
is_array($item) => new $arg($item),
98+
$item instanceof $arg => $item,
99+
$case !== null => $arg::{$case->name},
100+
default => throw new Exception("必須傳入 array 或 array<{$arg}>")
101+
};
94102
}, $data[$key]),
95103
!$exists && $nullable && !$hasDefault => null,
96104
!$exists && $nullable && $hasDefault => $property->getDefaultValue(),

0 commit comments

Comments
 (0)