Collection Eloquent – object or array

CHUYỆN NGHỀNo Comments

You Are Here:Collection Eloquent – object or array

1. Về series Eloquent – Behind the Mask

Onthisday trên facebook thấy của tôi báo ngày này năm xưa tôi có tạo create một project đầu tiên bằng Laravel, tôi lại bồi hồi nhớ về những bỡ ngỡ khi lần đầu tiên tiếp xúc với RoutesControllerView hay sử dụng những câu truy vấn đến DB thật đơn giản với Eloquent.

Đối với tôi Laravel là 1 framework khá dễ để bắt đầu với một tâm thế của một sinh viên thích ăn xổi hồi đó. Tôi có thể đăng kí 1 url khá dễ dàng với Routes, cũng có thể truy vấn vào cơ sở dữ liệu và lấy dữ liệu ra mà chẳng cần quan tâm đến PDO hay mysqli.

Sau khi làm việc một thời gian gặp vài con bug cảm giác như mình không thể control được nó, lúc đó tôi đã nghĩ đến việc đọc code core của Laravel. Đặt vấn đề như sau, bạn có 1 Model là User bạn muốn lấy ra user thuộc Model đó. Với Eloquent bạn rất đơn giản chỉ cần thực hiện câu lệnh.

Tôi thực sự tò mò chỉ 1 câu lệnh đơn giản như vậy Eloquent đã phải làm rất nhiều thứ mà bạn ít nhất gặp khó khăn trong việc code PHP thuần. Với PHP thuần bạn phải làm gì để lấy ra tất cả bản ghi của 1 bảng ?

  1. Kết nối cơ sở dữ liệu bẳng PDO chẳng hạn
  2. Sử dụng câu SQL thuần: select * from users
  3. Đóng kết nối cơ sở dữ liệu

Series của tôi cũng xây dựng xoay quanh những việc mà Laravel đã làm sẵn cho chúng ta để hiểu hơn về framework này. Tất nhiên với kinh nghiệm cùng vốn kiến thức chưa nhiều của mình, tôi sẽ viết ra tất cả những gì tôi đã tìm hiều được và chắc chắn không thể không có những nhầm lần (yaoming). Hi vọng loạt bài viết sẽ giúp tôi và các bạn có một forum nhỏ cùng bàn luận về core của Laravel.

2. Đặt vấn đề

Một ngày đẹp trời bạn thực hiện câu lệnh quen thuộc để lấy ra tất cả bản ghi trong bảng user. Câu chuyện hết sức đơn giản nếu bạn sử dụng Eloquent trong Laravel

Kết quả trả ra Collection. Nó là một class được tích hợp sẵn các phương thức thường xuyên được sử dụng để xử lý dữ liệu làm giảm thiểu tối đa thời gian cho các lập trình viên. Đặc biệt là khi làm việc với API kết nối với database vì dữ liệu từ database trả về sẵn kiểu là Collection.

Để lấy ra thuộc tính name của Collection trên cũng đơn giản thôi. Bạn dùng câu lệnh

Bài toán đã được giải quyết nhưng dừng lại một chút, ta thấy collection kia vừa gọi theo kiểu object được vừa gọi theo kiểu array được. Vậy nó là object hay array.

3. Object và array trong PHP

Để khẳng định nó là object hay array thì ta đi qua một chút về hai khái niệm này trong PHP.

Array(Mảng) là danh sách  các phần tử có cùng kiểu dữ liệu và nó là một trong các kiểu dữ liệu trong php có độ phức tạp tính toán cao. Có 2 loại mảng là mảng một chiều hoặc mảng nhiều chiều. Riêng với PHP thì các phần tử của mảng có thể không cùng kiểu dữ liệuvà các phần tử của mảng được truy xuất thông qua các chỉ mục(vị trí) của nó nằm trong mảng.

Khởi tạo vào gọi 1 phần tử array trong php có rất nhiều cách để đơn giản ta sử dụng cú pháp sau

Còn với object việc khởi tạo và gọi ra như sau

Như kết quả ta thấy khi ta gọi đến thuộc tính trong object mà sử dụng cú pháp [] sẽ thông báo lỗi ngay. Vậy điều gì đã khiến Collection trong laravel có thể sử dụng cả cú pháp gọi của object và array ?

4. Nhìn lại code Laravel

Cùng đi vào phân tích một chút xem Laravel đã làm gì để biến một collection linh hoạt đến vậy.

Đầu tiên model User extend từ Authenticatable. class này lại extend  Model trong thư mục vendor. Túm váy lại là khi ta gọi đến User::all() thực tế là gọi hàm all() trong class Model trong thư mục vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php. Trong static function all() này cũng cũng tạo ra new 1 class Builder mới. Chúng ta đừng vội quan tâm đến hàm này vội mà hãy nhìn phần đầu của class Model nó implements ArrayAccess. Nếu bạn nào hay đọc code php thuần thì đã đã nhận ra vẫn đề nằm ở đây.

PHP thuần cung cấp cho ta một số class và interfaces được xây dựng sẵn. Các class và interfaces này cho phép nhà phát triển PHP thêm các tính năng vào ngôn ngữ thường được dành riêng cho những framework.

Lên document của php đọc thì ta thấy nó cung cấp cho ta 4 abstract  method

Tức là bây giờ Model của chúng ta do đã implements ArrayAccess cần phải override lại 4 method đấy.

Mò xuống code thì đúng là Laravel đã làm như vậy. Điều chúng ta quan tâm ở đây là điều gì đã xảy ra khi chúng ta cố tình gọi thuộc tính của 1 object theo cú pháp của một array

Khi chúng ta gọi như vậy, bằng 1 cách magic của nhà phát triển php, mặc định chúng ta đã gọi đến abstract offsetGet. Tôi đã thử debug ra kết quả là như vậy.

Cùng xem hàm này xử lí gì nhé.

nó truyền vào 1 param khi dump ra bạn sẽ nhận được giá trị là key của 1 mảng. Cụ thể ở đây là name. Tìm tiếp vào hàm getAttribute($offset) xem nó làm gì.

Tôi đã lục tung cả class Model ra mà không thể tìm thấy hàm getAttribute(). Class Model cũng không extend class nào khác, tưởng như đã đi vào đường cụt thì tôi nhìn thấy cú pháp này trong phần đầu của class Model

Không còn nghi ngờ gì nữa, Model ở đây đã sử dụngTrait (Tìm hiểu về Trait).  Kiên nhẫn một chút tôi đã tìm thấy hàm getAttribute() trong thư mục vendor\laravel\framework\src\Illuminate\Database\Eloquent\Concerns\HasAttributes.php.

Mọi chuyện giờ chỉ là đọc tiếp code của function này thôi. Sau một hồi gọi hàm thì chúng ta dừng lại ở hàm getAttributeFromArray($key).

Câu trả lời cuối cùng đã có, thực tế ta gọi $user[‘name’] là ta return ra một $attribute từ model.

5. Tổng kết

Vậy là sau một hồi suy luận ta đã hiểu được tại sao collection nó lại linh hoạt sử dụng được cú pháp của array. Thực ra collection trả về 1 object nhưng do implements ArrayAccess  nên có thể sử dụng có pháp array.

Lời cuối xin cảm ơn các bạn đã đọc bài viết của mình. Bài tiếp theo mình sẽ chỉ ra xem Laravel đã kết nối với DB như thế nào ?

About the author:

Top