Mảng thuộc tính đã gõ trong php của các đối tượng

Với PHP 7, bạn có thể chọn viết mã an toàn hơn nhiều so với trước đây, nhờ gợi ý kiểu vô hướng và kiểu trả về

function repeat(string $text, int $times) : string;

Nhưng còn mảng thì sao? . Đối với IDE, bạn có thể thêm nhận xét PhpDoc

/**
 * @return User[]
 */
function allUsers() : array;

Giờ đây, các IDE như PhpStorm có thể giúp hoàn thành mã cho các mục trong mảng được trả về. Nhưng chúng tôi không thể hưởng lợi từ bất kỳ kiểm tra nào trong thời gian chạy, như với các gợi ý kiểu thực

Đối với các đối số, có một cách giải quyết một phần, sử dụng các đối số biến đổi. Thực hiện chức năng sau

/**
 * @param User[] $users
 */
function deleteUsers(array $users);

Với các đối số matrixdic, chúng ta có thể viết lại nó thành

function deleteUsers(User ...$users);

Cách sử dụng cũng thay đổi, thành

/**
 * @param User[] $users
 */
function deleteUsers(array $users);
1 Trong lệnh gọi này, đối số
/**
 * @param User[] $users
 */
function deleteUsers(array $users);
2 sẽ được “giải nén” thành các biến đơn lẻ và trong chính phương thức đó, nó được “đóng gói” lại thành một mảng
/**
 * @param User[] $users
 */
function deleteUsers(array $users);
2. Mỗi mặt hàng được xác nhận thuộc loại
/**
 * @param User[] $users
 */
function deleteUsers(array $users);
4.
/**
 * @param User[] $users
 */
function deleteUsers(array $users);
2 cũng có thể là một iterator, nó sẽ được chuyển đổi thành một mảng

Thật không may, không có cách giải quyết tương tự cho các kiểu trả về và nó chỉ hoạt động cho đối số cuối cùng

Xem thêm. Nhập gợi ý trong PHP 7 – mảng đối tượng

Tôi đã sử dụng kỹ thuật này rất nhiều trong mã PHP 7, nhưng tôi đã tìm thấy một kỹ thuật khác thậm chí còn tốt hơn và không có các lỗi đã đề cập

đối tượng bộ sưu tập

Mỗi khi tôi cần một mảng đối tượng, tôi tạo một lớp thay thế. Đây là một ví dụ đơn giản

class Users extends ArrayIterator
{
    public function __construct(User ...$users)
    {
        parent::__construct($users);
    }
    public function current() : User
    {
        return parent::current();
    }
    public function offsetGet($offset) : User
    {
        return parent::offsetGet($offset);
    }
}

Bộ sưu tập này kéo dài

/**
 * @param User[] $users
 */
function deleteUsers(array $users);
6, vì vậy nó có thể được sử dụng gần giống như một mảng. lặp lại với
/**
 * @param User[] $users
 */
function deleteUsers(array $users);
7 và truy cập các phần tử với
/**
 * @param User[] $users
 */
function deleteUsers(array $users);
8. Hàm mảng không dùng được nhưng với
/**
 * @param User[] $users
 */
function deleteUsers(array $users);
9 thì có thể chuyển thành mảng bình thường

Lưu ý rằng bạn chỉ có thể thay đổi gợi ý kiểu trả về để hạn chế hơn trong lớp cha. Vì vậy, việc ghi đè

function deleteUsers(User ...$users);
0 sẽ không hoạt động và đối tượng sẽ ở trạng thái chưa được xác thực cho đến khi từng mục được truy cập

Nếu chúng ta không cần giao diện

function deleteUsers(User ...$users);
1 để truy cập các phần tử với
/**
 * @param User[] $users
 */
function deleteUsers(array $users);
8, thì có một giải pháp cho điều đó. đóng gói trình lặp mảng và chỉ hiển thị những gì bạn cần

class Users extends IteratorIterator
{
    public function __construct(User ...$users)
    {
        parent::__construct(new ArrayIterator($users));
    }
    public function current() : User
    {
        return parent::current();
    }
}

(bạn có bao giờ tự hỏi, tại sao

function deleteUsers(User ...$users);
3 lại tồn tại không? Ở đây tôi đã tìm thấy một trường hợp sử dụng. )

Đối tượng

function deleteUsers(User ...$users);
4 này chỉ có thể được tạo với các phần tử
/**
 * @param User[] $users
 */
function deleteUsers(array $users);
4, nhờ các đối số hàm tạo biến đổi. Chuyển bất cứ thứ gì khác cho hàm tạo sẽ dẫn đến một
function deleteUsers(User ...$users);
6 có thể bắt được

new Users($user1, $user2, $user3);

Và nó thậm chí là bất biến, nó không thể thay đổi sau khi khởi tạo. Nhưng nếu chúng ta cần thay đổi nó, bây giờ chúng ta có thể thêm các phương thức an toàn cho điều đó, như

public function add(User $user)
{
    $this->getInnerIterator()->append($user);
}
public function set(int $key, User $user)
{
    $this->getInnerIterator()->offsetSet($key, $user);
}

Bạn cũng có thể làm cho nó có thể đếm được (vì chúng tôi biết, trình vòng lặp bên trong thực hiện

function deleteUsers(User ...$users);
7)

    public function count() : int
    {
        return $this->getInnerIterator()->count();
    }

Hàm mảng

Như đã đề cập trước đây, nếu bạn cần các hàm mảng, bạn luôn có thể chuyển đổi đối tượng thành một mảng bằng

/**
 * @param User[] $users
 */
function deleteUsers(array $users);
9. Nhưng có một giải pháp khác thường hợp lý hơn. di chuyển chức năng vào lớp bộ sưu tập. Đối với các hàm sắp xếp, thật dễ dàng vì chúng đã là một phần của
/**
 * @param User[] $users
 */
function deleteUsers(array $users);
6, vì vậy chúng ta có thể thực hiện tương tự như với
class Users extends ArrayIterator
{
    public function __construct(User ...$users)
    {
        parent::__construct($users);
    }
    public function current() : User
    {
        return parent::current();
    }
    public function offsetGet($offset) : User
    {
        return parent::offsetGet($offset);
    }
}
0 ở trên

Nhưng hãy lấy một ví dụ khác và hợp nhất hai bộ sưu tập người dùng

public function merge(Users $other)
{
    return new Users(
        array_merge(
            iterator_to_array($this),
            iterator_to_array($other)
        )
    );
}

Bây giờ nó có thể được sử dụng như

/**
 * @return User[]
 */
function allUsers() : array;
0

Khi thêm các phương thức vào các đối tượng bộ sưu tập, hãy càng cụ thể càng tốt để chuyển logic vào bộ sưu tập thuộc về đó. Ví dụ: thay vì tạo một phương thức

class Users extends ArrayIterator
{
    public function __construct(User ...$users)
    {
        parent::__construct($users);
    }
    public function current() : User
    {
        return parent::current();
    }
    public function offsetGet($offset) : User
    {
        return parent::offsetGet($offset);
    }
}
1 chung chung, hãy tạo chính xác (các) phương thức sắp xếp mà bạn cần

/**
 * @return User[]
 */
function allUsers() : array;
1

Điều đó làm cho mã máy khách rõ ràng hơn nhiều (điều không thể thực hiện được với mảng)

/**
 * @return User[]
 */
function allUsers() : array;
2

Với các phương thức lọc/ánh xạ/thu nhỏ, chúng tôi cũng có tùy chọn để làm việc với các đường ống thu thập, như tôi đã giải thích trong một bài đăng trên blog trước đây. Đường ống thu thập trong PHP

Lôgic tên miền

Khi tôi cần một tập hợp các đối tượng, trước tiên tôi thường tạo một lớp đơn giản, mở rộng

function deleteUsers(User ...$users);
3, như trong ví dụ trên. Ưu điểm rõ ràng là an toàn kiểu, nhưng nó cũng giúp dễ dàng thêm logic miền vào đúng chỗ sau này. Ngay khi tôi có các phương thức hoạt động trên một tập hợp các đối tượng, tôi có thể thêm chúng trực tiếp vào lớp tập hợp, nơi chúng thuộc về một cách tự nhiên. Nếu không, chúng có thể kết thúc trong một số lớp tiện ích hoặc trình trợ giúp (Ngừng sử dụng Trình trợ giúp. ) hoặc thậm chí trong mã máy khách sử dụng bộ sưu tập

Hãy coi đây là một phần của trò chơi bài

/**
 * @return User[]
 */
function allUsers() : array;
3

Nó kết hợp logic trò chơi cấp cao với các chi tiết triển khai cấp thấp. Với một đối tượng bộ sưu tập thẻ, chúng ta có thể di chuyển các phương thức hoạt động trên thẻ ở đó và giữ lớp Game ở một mức trừu tượng

/**
 * @return User[]
 */
function allUsers() : array;
4

giao diện

Trước tiên, việc xác định bộ sưu tập là giao diện thường hữu ích. Nó mở rộng giao diện

class Users extends ArrayIterator
{
    public function __construct(User ...$users)
    {
        parent::__construct($users);
    }
    public function current() : User
    {
        return parent::current();
    }
    public function offsetGet($offset) : User
    {
        return parent::offsetGet($offset);
    }
}
3 và chứa ít nhất phương thức
class Users extends ArrayIterator
{
    public function __construct(User ...$users)
    {
        parent::__construct($users);
    }
    public function current() : User
    {
        return parent::current();
    }
    public function offsetGet($offset) : User
    {
        return parent::offsetGet($offset);
    }
}
4 với kiểu trả về được chỉ định

Ví dụ tối thiểu

/**
 * @return User[]
 */
function allUsers() : array;
5

Với cách triển khai mặc định như được bao bọc

/**
 * @param User[] $users
 */
function deleteUsers(array $users);
6

/**
 * @return User[]
 */
function allUsers() : array;
6

Tại sao nó hữu ích?

Thực hiện có thể trao đổi

Đầu tiên, nếu mã của bạn sẽ được sử dụng bởi các bên thứ ba, họ sẽ có thể hoán đổi việc triển khai. Ví dụ yêu thích của tôi là lười tải các bộ sưu tập với trình tạo để có hiệu suất tốt hơn với các bộ sưu tập lớn

/**
 * @return User[]
 */
function allUsers() : array;
7

mà sau đó có thể được khởi tạo như thế này

/**
 * @return User[]
 */
function allUsers() : array;
8

Ở đây, các đối tượng Người dùng không được tìm nạp từ cơ sở dữ liệu trước khi bạn thực sự lặp lại bộ sưu tập tải chậm. Vì các trình tạo chỉ có thể được lặp lại một lần, nên bộ sưu tập sẽ không giữ tất cả các đối tượng trong bộ nhớ cùng một lúc

Khả năng mở rộng với trang trí

Thứ hai, bạn sẽ có thể mở rộng lớp với các trình trang trí, bao bọc thể hiện ban đầu và triển khai cùng một giao diện, nhưng thêm hành vi bổ sung. Bạn thậm chí có thể sử dụng bộ sưu tập để trang trí tất cả các mặt hàng một cách nhanh chóng

Giả sử việc triển khai

class Users extends ArrayIterator
{
    public function __construct(User ...$users)
    {
        parent::__construct($users);
    }
    public function current() : User
    {
        return parent::current();
    }
    public function offsetGet($offset) : User
    {
        return parent::offsetGet($offset);
    }
}
6 mặc định trong trò chơi bài tuyệt vời của chúng ta có một phương thức
class Users extends ArrayIterator
{
    public function __construct(User ...$users)
    {
        parent::__construct($users);
    }
    public function current() : User
    {
        return parent::current();
    }
    public function offsetGet($offset) : User
    {
        return parent::offsetGet($offset);
    }
}
7 trả về quân bài phù hợp và xếp hạng dưới dạng văn bản thuần túy, đồng thời thêm một trình trang trí cho biểu diễn HTML

/**
 * @return User[]
 */
function allUsers() : array;
9

Bây giờ chúng ta cũng có thể viết một trình trang trí cho bộ sưu tập, lấy bất kỳ bộ sưu tập

class Users extends ArrayIterator
{
    public function __construct(User ...$users)
    {
        parent::__construct($users);
    }
    public function current() : User
    {
        return parent::current();
    }
    public function offsetGet($offset) : User
    {
        return parent::offsetGet($offset);
    }
}
8 nào và trang trí các phần tử của nó bằng
class Users extends ArrayIterator
{
    public function __construct(User ...$users)
    {
        parent::__construct($users);
    }
    public function current() : User
    {
        return parent::current();
    }
    public function offsetGet($offset) : User
    {
        return parent::offsetGet($offset);
    }
}
9

Thuộc tính được gõ trong PHP là gì?

Với các thuộc tính đã nhập, bạn có thể đặt một loại cho tất cả các thuộc tính của lớp . Khi một loại được đặt, công cụ PHP sẽ ngăn mọi người đặt một loại khác cho thuộc tính lớp. Đoạn mã trên sẽ đảm bảo rằng Ví dụ. Thuộc tính $birthday sẽ luôn là một đối tượng DateTime.

Làm cách nào để lấy các thuộc tính của một đối tượng trong PHP?

Hàm get_object_vars() là một hàm có sẵn trong PHP được sử dụng để lấy các thuộc tính của đối tượng đã cho.

$this trong PHP là gì?

$đây là từ khóa dành riêng trong PHP đề cập đến đối tượng gọi . Nó thường là đối tượng mà phương thức thuộc về, nhưng có thể là đối tượng khác nếu phương thức được gọi tĩnh từ ngữ cảnh của đối tượng phụ. Từ khóa này chỉ áp dụng cho các phương pháp nội bộ.

Làm cách nào để đặt quyền truy cập vào các thuộc tính và phương thức trong PHP?

Khi bạn có một đối tượng, bạn có thể sử dụng ký hiệu -> để truy cập các phương thức và thuộc tính của đối tượng. $object -> tên thuộc tính $object -> tên phương thức ([ arg,. ] ) Phương thức là hàm nên chúng có thể nhận đối số và trả về giá trị. $clan = $rasmus->gia đình('extended');