Trước khi PHP 8 ra đời, những khi bạn không chắc chắn về kiểu của thuộc tính hay giá trị trả về, chúng ta sẽ bỏ qua, không chỉ định kiểu cho chúng. Nếu bạn sử dụng một IDE như PHPStorm, dockBlock sẽ đánh dấu các thuộc tính đó với kiểu dữ liệu mixed.
Kiểu dữ liệu mixed
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token comment">/** * Handle an incoming request. * * @param mixed $request * @param Closure $next * @return mixed */</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">handle</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">,</span> Closure <span class="token variable">$next</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$next</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Điều này cũng có một vài lợi ích. Nhưng về cơ bản, nó không thực sự được kiểm tra kiểu bằng trình biên dịch của PHP.
Để giảm bớt vấn đề này, PHP 8 đã giới thiệu kiểu dữ liệu mixed
, có thể sử dụng để gán cho thuộc tính hoặc giá trị trả về.
Về cơ bản, kiểu dữ liệu mixed
sẽ tương đương với: array
hoặc bool
hoặc callable
hoặc int
hoặc float
hoặc null
hoặc object
hoặc resource
hoặc string
. Vì vậy, bất cứ khi nào bạn không chắc chắn về kiểu dữ liệu, hãy sử dụng mixed.
Ví dụ bên trên có thể viết lại thành:
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token comment">/** * Handle an incoming request. * * @param mixed $request * @param Closure $next * @return mixed */</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">handle</span><span class="token punctuation">(</span>mixed <span class="token variable">$request</span><span class="token punctuation">,</span> Closure <span class="token variable">$next</span><span class="token punctuation">)</span><span class="token punctuation">:</span> mixed <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$next</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Và bây giờ, mọi thứ sẽ rõ ràng hơn. Và trình biên dịch của PHP biết sẽ phải làm gì với những thuộc tính/giá trị này.
Các quy tắc
Kiểu mixed
không thể nullable
Bình thường khi muốn định kiểu dữ liệu hoặc null
, chúng ta phải thêm dấu ?
trước kiểu dữ liệu. Ví dụ:
1 2 3 4 5 6 | <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span>string <span class="token variable">$text</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token comment">// $text bắt buộc phải là string</span> <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span><span class="token operator">?</span>string <span class="token variable">$text</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token comment">// $text là string hoặc null</span> |
Nhưng đối với kiểu mixed
chúng ta không thể sử dụng như vậy. Bởi vì kiểu mixed
đã bao gồm null
.
1 2 3 4 5 6 | <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span><span class="token operator">?</span>mixed <span class="token variable">$arg</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token comment">// Fatal error: Mixed types cannot be nullable, null is already part of the mixed type.</span> <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token operator">?</span>mixed <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token comment">// Fatal error: Mixed types cannot be nullable, null is already part of the mixed type.</span> |
Phải có giá trị trả về cho return kiểu mixed
Khi sử dụng kiểu return là mixed
, một giá trị phải được trả về.
1 2 3 4 5 6 7 | <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> mixed <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Uncaught TypeError: Return value of getName() must be of </span> <span class="token comment">// the type mixed, none returned</span> |
Kiểu của thuộc tính có thể mở rộng khi kế thừa
Một thuộc tính có kiểu dữ liệu bất kỳ trong class cha có thể mở rộng thành mixed
trong class con.
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">class</span> <span class="token class-name">A</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span>string <span class="token variable">$value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">B</span> <span class="token keyword">extends</span> <span class="token class-name">A</span> <span class="token punctuation">{</span> <span class="token comment">// hoạt động</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span>mixed <span class="token variable">$value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Nhưng ngược lại thì không được.
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">class</span> <span class="token class-name">A</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span>mixed <span class="token variable">$value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">B</span> <span class="token keyword">extends</span> <span class="token class-name">A</span> <span class="token punctuation">{</span> <span class="token comment">// Fatal error</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span>string <span class="token variable">$value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Kiểu của return có thể thu hẹp khi kế thừa
Ngược lại với kiểu thuộc tính, một method có kiểu trả về là mixed
trong class cha có thể thu hẹp thành kiểu bất kỳ trong class con.
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">class</span> <span class="token class-name">A</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> mixed <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">B</span> <span class="token keyword">extends</span> <span class="token class-name">A</span> <span class="token punctuation">{</span> <span class="token comment">// hoạt động</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> string <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Ngược lại thì không hợp lệ.
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">class</span> <span class="token class-name">C</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> string <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">D</span> <span class="token keyword">extends</span> <span class="token class-name">C</span> <span class="token punctuation">{</span> <span class="token comment">// Fatal error</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> mixed <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Giả định kiểu dữ liệu mixed
nếu không có kiểu dữ liệu nào được chỉ định
Khi không có kiểu nào được chỉ định, việc kiểm tra kiểu khi kế thừa được thực hiện giống với kiểu mixed
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <span class="token keyword">class</span> <span class="token class-name">A</span> <span class="token punctuation">{</span> <span class="token comment">// $value được hiểu là có kiểu mixed</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span><span class="token variable">$value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">B</span> <span class="token keyword">extends</span> <span class="token class-name">A</span> <span class="token punctuation">{</span> <span class="token comment">// kiểu mixed được chỉ định, không thay đổi so với class cha</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span>mixed <span class="token variable">$value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">C</span> <span class="token keyword">extends</span> <span class="token class-name">B</span> <span class="token punctuation">{</span> <span class="token comment">// không có kiểu dữ liệu nào được chỉ định</span> <span class="token comment">// $value được hiểu là có kiểu dữ liệu mixed giống class cha</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span><span class="token variable">$value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">D</span> <span class="token keyword">extends</span> <span class="token class-name">B</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span>mixed <span class="token variable">$value</span> <span class="token operator">=</span> <span class="token constant">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Kiểm tra kiểu return nếu không được chỉ định
Khi không có kiểu return nào được chỉ định, việc kiểm tra kiểu khi kế thừa được thực hiện giống với kiểu mixed
hoặc void
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <span class="token keyword">class</span> <span class="token class-name">A</span> <span class="token punctuation">{</span> <span class="token comment">// không chỉ định kiểu return, hiểu là mixed|void</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">B</span> <span class="token keyword">extends</span> <span class="token class-name">A</span> <span class="token punctuation">{</span> <span class="token comment">// chỉ định kiểu return là mixed</span> <span class="token comment">// kiểu mixed được hiểu là thu hẹp của 'mixed|void'</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> mixed <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">C</span> <span class="token keyword">extends</span> <span class="token class-name">B</span> <span class="token punctuation">{</span> <span class="token comment">// không chỉ định kiểu return, hiểu là 'mixed|void'</span> <span class="token comment">// 'mixed|void' là mở rộng của mixed.</span> <span class="token comment">// Fatal error</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">D</span> <span class="token keyword">extends</span> <span class="token class-name">B</span> <span class="token punctuation">{</span> <span class="token comment">// void là kiểu dữ liệu khác với mixed</span> <span class="token comment">// Fatal error</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> void <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Tham khảo:
https://wiki.php.net/rfc/mixed_type_v2
https://wiki.php.net/rfc/mixed-typehint
Cảm ơn các bạn đã đọc bài viết!