Chúng ta có thể khởi tạo đặc điểm trong PHP không?

Giảm thiểu trùng lặp mã thông qua tổ chức tốt hơn và tái sử dụng mã là mục tiêu quan trọng của Lập trình hướng đối tượng. Nhưng trong PHP đôi khi có thể khó khăn do những hạn chế của mô hình kế thừa duy nhất mà nó sử dụng;

Các ngôn ngữ như C++ và Python cho phép chúng ta kế thừa từ nhiều lớp, điều này giải quyết vấn đề này ở một mức độ nào đó và mixin trong Ruby cho phép chúng ta kết hợp chức năng của một hoặc nhiều lớp mà không cần sử dụng tính kế thừa. Nhưng đa kế thừa có các vấn đề như vấn đề Vấn đề kim cương và mixin có thể là một cơ chế phức tạp để làm việc với

Trong bài viết này, tôi sẽ thảo luận về các đặc điểm, một tính năng mới được giới thiệu trong PHP 5. 4 để khắc phục những vấn đề như vậy. Bản thân khái niệm về đặc điểm không có gì mới đối với lập trình và được sử dụng trong các ngôn ngữ khác như Scala và Perl. Chúng cho phép chúng tôi sử dụng lại mã theo chiều ngang giữa các lớp độc lập trong các hệ thống phân cấp lớp khác nhau

Một đặc điểm trông như thế nào

Một đặc điểm tương tự như một lớp trừu tượng không thể tự khởi tạo (mặc dù nó thường được so sánh với một giao diện). Tài liệu PHP định nghĩa các đặc điểm như sau

Đặc điểm là một cơ chế để tái sử dụng mã trong các ngôn ngữ kế thừa đơn lẻ như PHP. Một Đặc điểm nhằm giảm bớt một số hạn chế của thừa kế đơn lẻ bằng cách cho phép nhà phát triển sử dụng lại các bộ phương thức một cách tự do trong một số lớp độc lập sống trong các hệ thống phân cấp lớp khác nhau

Hãy xem xét ví dụ này

Sẽ là một vấn đề nếu cả hai lớp đều cần một số chức năng chung, chẳng hạn như tạo cả hai lớp đơn. Vì PHP không hỗ trợ đa kế thừa, nên mỗi lớp sẽ phải triển khai mã cần thiết để hỗ trợ mẫu Singleton hoặc sẽ có một hệ thống phân cấp thừa kế không hợp lý. Đặc điểm cung cấp một giải pháp cho chính xác loại vấn đề này

Đặc điểm

2 có triển khai trực tiếp mẫu Singleton với một phương thức tĩnh
3 tạo một đối tượng của lớp bằng cách sử dụng đặc điểm này (nếu nó chưa được tạo) và trả về nó

Hãy thử tạo các đối tượng của các lớp này bằng phương thức

3

Chúng ta có thể thấy rằng

5 là một đối tượng của
6 và
7 là một đối tượng của
8, nhưng cả hai hiện đang hoạt động như những người độc thân. Phương thức từ
2 đã được đưa vào theo chiều ngang cho các lớp sử dụng nó

Các đặc điểm không áp đặt bất kỳ ngữ nghĩa bổ sung nào cho lớp. Theo một cách nào đó, bạn có thể coi nó như một cơ chế sao chép và dán được trình biên dịch hỗ trợ trong đó các phương thức của đặc điểm được sao chép vào lớp soạn thảo

Nếu chúng ta chỉ đơn giản là phân lớp phụ

6 từ cha mẹ có thuộc tính riêng tư
1, thì thuộc tính đó sẽ không được hiển thị trong kết xuất của
2. Và với những đặc điểm, đó là

Class [  class FileReader ] {
  @@ /home/shameer/workplace/php54/index.php 19-22

  - Constants [0] {
  }
  - Static properties [1] {
    Property [ private static $_instance ]
  }
  - Static methods [1] {
    Method [  static public method instance ] {
      @@ /home/shameer/workplace/php54/index.php 6 - 11
    }
  }
  - Properties [0] {
  }
  - Methods [0] {
  }
}

Nhiều đặc điểm

Cho đến nay, chúng tôi chỉ sử dụng một đặc điểm với một lớp, nhưng trong một số trường hợp, chúng tôi có thể cần kết hợp chức năng của nhiều đặc điểm

sayHello() . " " . $world->sayWorld(); //Hello World

Ở đây chúng ta có hai đặc điểm,

3 và
4. Đặc điểm
3 chỉ có thể nói “Xin chào” và đặc điểm
4 có thể nói “Thế giới”. Trong lớp
7, chúng tôi đã áp dụng
3 và
4 để đối tượng
7 sẽ có các phương thức từ cả hai đặc điểm và có thể nói “Xin chào thế giới”

Đặc điểm bao gồm các đặc điểm

Khi ứng dụng phát triển, rất có thể chúng ta sẽ có một tập hợp các đặc điểm được sử dụng trên các lớp khác nhau. PHP5. 4 cho phép chúng ta có các tính trạng bao gồm các tính trạng khác để chúng ta có thể chỉ bao gồm một thay vì một số tính trạng trong tất cả các lớp này. Điều này cho phép chúng tôi viết lại ví dụ trước như sau

sayHello() . " " . $world->sayWorld(); //Hello World

Ở đây, chúng tôi đã tạo đặc điểm

Class [  class FileReader ] {
  @@ /home/shameer/workplace/php54/index.php 19-22

  - Constants [0] {
  }
  - Static properties [1] {
    Property [ private static $_instance ]
  }
  - Static methods [1] {
    Method [  static public method instance ] {
      @@ /home/shameer/workplace/php54/index.php 6 - 11
    }
  }
  - Properties [0] {
  }
  - Methods [0] {
  }
}
1, sử dụng đặc điểm Hello và World, và đưa nó vào
7. Vì đặc điểm
Class [  class FileReader ] {
  @@ /home/shameer/workplace/php54/index.php 19-22

  - Constants [0] {
  }
  - Static properties [1] {
    Property [ private static $_instance ]
  }
  - Static methods [1] {
    Method [  static public method instance ] {
      @@ /home/shameer/workplace/php54/index.php 6 - 11
    }
  }
  - Properties [0] {
  }
  - Methods [0] {
  }
}
1 có các phương thức từ hai đặc điểm còn lại, nên nó cũng giống như việc chúng ta tự đưa hai đặc điểm đó vào lớp

thứ tự ưu tiên

Như tôi đã đề cập, các đặc điểm hoạt động như thể các phương thức của chúng đã được sao chép và dán vào các lớp sử dụng chúng và chúng hoàn toàn được làm phẳng trong định nghĩa của các lớp. Có thể có các phương thức có cùng tên trong các đặc điểm khác nhau hoặc trong chính lớp đó. Bạn có thể tự hỏi cái nào sẽ có sẵn trong đối tượng của lớp con

Thứ tự ưu tiên là

  1. các phương thức của một đặc điểm ghi đè các phương thức kế thừa từ lớp cha
  2. các phương thức được định nghĩa trong lớp hiện tại sẽ ghi đè các phương thức từ một đặc điểm

Điều này được làm rõ trong ví dụ sau

sayHello() . " " . $this->sayWorld();
    }

    function sayBaseWorld() {
        echo $this->sayHello() . " " . parent::sayWorld();
    }
}

class Base
{
    function sayWorld(){
        return "Base World";
    }
}

class HelloWorld extends Base
{
    use Hello;
    function sayWorld() {
        return "World";
    }
}

$h =  new HelloWorld();
$h->sayHelloWorld(); // Hello World
$h->sayBaseWorld(); // Hello Base World

Chúng ta có một lớp

Class [  class FileReader ] {
  @@ /home/shameer/workplace/php54/index.php 19-22

  - Constants [0] {
  }
  - Static properties [1] {
    Property [ private static $_instance ]
  }
  - Static methods [1] {
    Method [  static public method instance ] {
      @@ /home/shameer/workplace/php54/index.php 6 - 11
    }
  }
  - Properties [0] {
  }
  - Methods [0] {
  }
}
1 bắt nguồn từ lớp
Class [  class FileReader ] {
  @@ /home/shameer/workplace/php54/index.php 19-22

  - Constants [0] {
  }
  - Static properties [1] {
    Property [ private static $_instance ]
  }
  - Static methods [1] {
    Method [  static public method instance ] {
      @@ /home/shameer/workplace/php54/index.php 6 - 11
    }
  }
  - Properties [0] {
  }
  - Methods [0] {
  }
}
5 và cả hai lớp đều có một phương thức tên là
Class [  class FileReader ] {
  @@ /home/shameer/workplace/php54/index.php 19-22

  - Constants [0] {
  }
  - Static properties [1] {
    Property [ private static $_instance ]
  }
  - Static methods [1] {
    Method [  static public method instance ] {
      @@ /home/shameer/workplace/php54/index.php 6 - 11
    }
  }
  - Properties [0] {
  }
  - Methods [0] {
  }
}
6 nhưng với cách triển khai khác nhau. Ngoài ra, chúng tôi đã bao gồm đặc điểm
3 trong lớp
Class [  class FileReader ] {
  @@ /home/shameer/workplace/php54/index.php 19-22

  - Constants [0] {
  }
  - Static properties [1] {
    Property [ private static $_instance ]
  }
  - Static methods [1] {
    Method [  static public method instance ] {
      @@ /home/shameer/workplace/php54/index.php 6 - 11
    }
  }
  - Properties [0] {
  }
  - Methods [0] {
  }
}
1

Chúng ta có hai phương thức,

Class [  class FileReader ] {
  @@ /home/shameer/workplace/php54/index.php 19-22

  - Constants [0] {
  }
  - Static properties [1] {
    Property [ private static $_instance ]
  }
  - Static methods [1] {
    Method [  static public method instance ] {
      @@ /home/shameer/workplace/php54/index.php 6 - 11
    }
  }
  - Properties [0] {
  }
  - Methods [0] {
  }
}
9 và
sayHello() . " " . $world->sayWorld(); //Hello World
0, phương thức đầu tiên gọi
Class [  class FileReader ] {
  @@ /home/shameer/workplace/php54/index.php 19-22

  - Constants [0] {
  }
  - Static properties [1] {
    Property [ private static $_instance ]
  }
  - Static methods [1] {
    Method [  static public method instance ] {
      @@ /home/shameer/workplace/php54/index.php 6 - 11
    }
  }
  - Properties [0] {
  }
  - Methods [0] {
  }
}
6 tồn tại trong cả hai lớp cũng như trong đặc điểm. Nhưng ở đầu ra, chúng ta có thể thấy cái từ lớp con đã được gọi. Nếu chúng ta cần tham chiếu phương thức từ lớp cha, chúng ta có thể làm như vậy bằng cách sử dụng từ khóa cha như trong phương thức
sayHello() . " " . $world->sayWorld(); //Hello World
0

Giải quyết xung đột và bí danh

Khi sử dụng nhiều đặc điểm, có thể xảy ra trường hợp các đặc điểm khác nhau sử dụng cùng một tên phương thức. Ví dụ: PHP sẽ báo lỗi nghiêm trọng nếu bạn cố chạy đoạn mã sau do xung đột tên phương thức

play();

Những xung đột về đặc điểm như vậy không được giải quyết tự động cho bạn. Thay vào đó, bạn phải chọn phương thức nào sẽ được sử dụng bên trong lớp soạn thảo bằng cách sử dụng từ khóa

sayHello() . " " . $world->sayWorld(); //Hello World
3

play(); //Playing music

Ở đây chúng tôi đã chọn sử dụng phương pháp

sayHello() . " " . $world->sayWorld(); //Hello World
4 của đặc điểm
sayHello() . " " . $world->sayWorld(); //Hello World
5 bên trong lớp sáng tác nên lớp
sayHello() . " " . $world->sayWorld(); //Hello World
6 sẽ chơi nhạc chứ không phải trò chơi

Trong ví dụ trên, một phương pháp đã được chọn thay vì phương pháp kia từ hai đặc điểm. Trong một số trường hợp, bạn có thể muốn giữ cả hai, nhưng vẫn tránh xung đột. Có thể giới thiệu một tên mới cho một phương thức trong một đặc điểm dưới dạng bí danh. Một bí danh không đổi tên phương thức, nhưng cung cấp một tên thay thế mà nó có thể được gọi. Bí danh được tạo bằng cách sử dụng từ khóa

sayHello() . " " . $world->sayWorld(); //Hello World
7

play(); //Playing music
$player->gamePlay(); //Playing a game

Bây giờ bất kỳ đối tượng nào của lớp

sayHello() . " " . $world->sayWorld(); //Hello World
6 sẽ có một phương thức
sayHello() . " " . $world->sayWorld(); //Hello World
9, giống như phương thức của
sayHello() . " " . $world->sayWorld(); //Hello World
0. Ở đây cần lưu ý rằng chúng tôi đã giải quyết mọi xung đột một cách rõ ràng, ngay cả sau khi đặt bí danh

Sự phản xạ

Reflection API là một trong những tính năng mạnh mẽ của PHP để phân tích cấu trúc bên trong của các giao diện, lớp và phương thức và thiết kế ngược chúng. Và vì chúng ta đang nói về các đặc điểm, bạn có thể muốn biết về sự hỗ trợ của Reflection API cho các đặc điểm. Trong PHP5. 4, bốn phương thức đã được thêm vào

sayHello() . " " . $world->sayWorld(); //Hello World
1 để lấy thông tin về các đặc điểm trong một lớp

Chúng ta có thể sử dụng

sayHello() . " " . $world->sayWorld(); //Hello World
2 để lấy một mảng gồm tất cả các đặc điểm được sử dụng trong một lớp. Phương thức
sayHello() . " " . $world->sayWorld(); //Hello World
3 sẽ chỉ trả về một mảng tên đặc điểm trong lớp đó.
sayHello() . " " . $world->sayWorld(); //Hello World
4 rất hữu ích để kiểm tra xem điều gì đó có phải là đặc điểm hay không

Trong phần trước, chúng ta đã thảo luận về việc đặt bí danh cho các đặc điểm để tránh xung đột do các đặc điểm có cùng tên.

sayHello() . " " . $world->sayWorld(); //Hello World
5 sẽ trả về một mảng bí danh đặc điểm được ánh xạ tới tên ban đầu của nó

Các tính năng khác

Ngoài những điều đã đề cập ở trên, còn có những tính năng khác làm cho các đặc điểm trở nên thú vị hơn. Chúng tôi biết rằng trong kế thừa cổ điển, các thuộc tính riêng của một lớp không thể được truy cập bởi các lớp con. Các đặc điểm có thể truy cập các thuộc tính hoặc phương thức riêng của các lớp tổng hợp và ngược lại. Đây là một ví dụ

0

Khi các đặc điểm được làm phẳng hoàn toàn thành lớp bao gồm chúng, bất kỳ thuộc tính hoặc phương thức nào của đặc điểm sẽ trở thành một phần của lớp đó và chúng tôi truy cập chúng giống như bất kỳ thuộc tính hoặc phương thức nào khác của lớp

Chúng ta thậm chí có thể có các phương thức trừu tượng trong một đặc điểm để thực thi lớp soạn thảo để thực hiện các phương thức này. Ví dụ

1

Ở đây chúng ta có một đặc điểm

sayHello() . " " . $world->sayWorld(); //Hello World
6 với một phương pháp trừu tượng
sayHello() . " " . $world->sayWorld(); //Hello World
7. Nó yêu cầu tất cả các lớp sử dụng đặc điểm này để thực hiện phương thức. Nếu không, PHP sẽ báo lỗi cho biết có một phương thức trừu tượng chưa được triển khai

Không giống như các đặc điểm trong Scala, các đặc điểm trong PHP có thể có một hàm tạo nhưng nó phải được khai báo ở chế độ công khai (một lỗi sẽ được đưa ra nếu là riêng tư hoặc được bảo vệ). Tuy nhiên, hãy thận trọng khi sử dụng các hàm tạo trong các đặc điểm, vì nó có thể dẫn đến các xung đột ngoài ý muốn trong các lớp soạn thảo

Bản tóm tắt

Đặc điểm là một trong những tính năng mạnh mẽ nhất được giới thiệu trong PHP 5. 4 và tôi đã thảo luận về hầu hết các tính năng của chúng trong bài viết này. Chúng cho phép các lập trình viên sử dụng lại các đoạn mã theo chiều ngang trên nhiều lớp mà không cần phải nằm trong cùng một hệ thống phân cấp thừa kế. Thay vì có ngữ nghĩa phức tạp, chúng cung cấp cho chúng ta cơ chế trọng lượng nhẹ để tái sử dụng mã. Mặc dù có một số nhược điểm với các đặc điểm, nhưng chắc chắn chúng có thể giúp cải thiện thiết kế ứng dụng của bạn, loại bỏ mã trùng lặp và làm cho ứng dụng trở nên KHÔ hơn

Hình ảnh qua Vlue / Shutterstock

Chia sẻ bài viết này

xấu hổ C

Shameer là một lập trình viên đam mê và đam mê mã nguồn mở đến từ Kerala, Ấn Độ. Anh ấy có kinh nghiệm phát triển web bằng Scala, PHP, Ruby, MySQL và JavaScript. Khi không làm việc, Shameer dành thời gian viết mã cho các dự án cá nhân, học hỏi, xem diễn viên trên màn hình, viết blog, v.v. Các lĩnh vực quan tâm cụ thể của ông bao gồm điện toán đám mây, quản trị hệ thống và cơ sở dữ liệu

Một đặc điểm có thể có hàm tạo trong PHP không?

Các đặc điểm trong ngôn ngữ Scala (một người kế thừa rất trưởng thành và thân thiện với RẮN của Java), không thể có hàm tạo có tham số. Có một lỗi trong PHP 5. 4. 11, cái thực sự cho phép đặt bí danh cho một phương thức siêu lớp

Làm cách nào để gọi một hàm đặc điểm trong PHP?

Một lớp có thể mở rộng một đặc điểm trong PHP không?

Chỉ có thể mở rộng các lớp học . Đặc điểm không phải là lớp học. Chúng có thể được sử dụng/bao gồm bởi các lớp nhưng bản thân chúng không phải là các lớp.

Sự khác biệt giữa đặc điểm và mixin trong PHP là gì?

Đặc điểm là giá trị bên ngoài thời gian biên dịch (chứ không phải mã được tạo từ nguồn bên ngoài). Sự khác biệt là tinh tế. Mixins thêm logic, Traits thêm dữ liệu như thông tin loại thời gian biên dịch .