Tôi nhận thấy rằng kể từ PHP5, các giao diện đã được thêm vào ngôn ngữ. Tuy nhiên, do PHP được gõ quá lỏng lẻo, nên dường như hầu hết các lợi ích của việc sử dụng giao diện đều bị mất. Tại sao điều này được bao gồm trong ngôn ngữ?
Tôi nhận thấy rằng kể từ PHP5, các giao diện đã được thêm vào ngôn ngữ. Tuy nhiên, do PHP được gõ quá lỏng lẻo, nên dường như hầu hết các lợi ích của việc sử dụng giao diện đều bị mất. Tại sao điều này được bao gồm trong ngôn ngữ?
Câu trả lời:
Ưu điểm chính của giao diện trong PHP là các lớp có thể thực hiện nhiều giao diện. Điều này cho phép bạn nhóm các lớp chia sẻ một số chức năng nhưng không nhất thiết phải chia sẻ một lớp cha. Một số ví dụ có thể bao gồm bộ nhớ đệm, đầu ra hoặc truy cập các thuộc tính của lớp theo một cách nhất định.
Trong mã của bạn, bạn có thể kiểm tra xem một lớp có thực hiện giao diện đã cho hay không thay vì kiểm tra tên lớp. Sau đó, mã của bạn sẽ vẫn hoạt động khi các lớp mới được thêm vào.
PHP cung cấp một số giao diện được xác định trước có thể có ích trong các tình huống khác nhau: http://php.net/manual/en/reserved.interfaces.php .
EDIT - Thêm một ví dụ
Nếu bạn có giao diện có tên MyInterface và bạn đang làm việc với nhiều đối tượng thuộc các lớp khác nhau có thể hoặc không thể chia sẻ một số chức năng, giao diện cho phép bạn làm một cái gì đó như thế này:
// Assume $objects is an array of instances of various classes
foreach($objects as $obj) {
if($obj instanceof MyInterface) {
$obj->a();
$obj->b();
$obj->c();
}
}
PHP được gõ lỏng lẻo, nhưng nó có thể được gõ mạnh về những thứ như tham số phương thức.
Hãy xem xét ví dụ sau:
interface Car { function go(); }
class Porsche { function go() {} }
function drive(Car $car) {}
$porsche = new Porsche();
drive($porsche);
Đoạn mã trên sẽ xuất ra:
Đối số 1 được truyền cho drive () phải triển khai giao diện Xe, ví dụ của Porsche đã cho
null
giá trị mặc định cho tham số, mặc dù.
drive
cần a Car
, thì việc vượt qua null
sẽ không hữu ích lắm đâu ...
function addView($name, Template $template, SecurityMode $securityMode = null, $methodName = null);
Bạn có thể có $methodName
nhưng không $securityMode
.
Các giao diện cho phép bạn thực hiện nguyên tắc đóng mở, duy trì cơ sở mã được ghép lỏng lẻo và triển khai nhiều mẫu thiết kế OOP tốt nhất.
Chẳng hạn, nếu một lớp chấp nhận một lớp khác làm đối số:
class A {
public function __construct(B $class_b) {
// use class b
$class_b->run();
}
}
Lớp A và lớp B của bạn bây giờ có khớp nối chặt chẽ và lớp A không thể sử dụng bất kỳ lớp nào khác ngoại trừ B. Gợi ý loại đảm bảo rằng bạn có loại đối số chính xác, nhưng hiện đã gắn kết mối quan hệ giữa A và B.
Hãy nói rằng bạn muốn lớp A có thể sử dụng tất cả các loại lớp có phương thức run (). Đây về cơ bản (nhưng không hoàn toàn) mẫu thiết kế LỆNH. Để giải quyết, thay vào đó bạn sẽ nhập gợi ý bằng giao diện thay vì lớp cụ thể. B họ sẽ triển khai giao diện đó và sẽ được chấp nhận làm đối số cho lớp A. Bằng cách này, lớp A có thể chấp nhận bất kỳ lớp nào sử dụng giao diện đó làm đối số cho hàm tạo của nó.
Loại mã hóa này được sử dụng trong hầu hết các mẫu thiết kế OOP và cho phép NHIỀU thay đổi mã dễ dàng hơn sau đó. Đây là một phần của các nguyên tắc cơ bản của lập trình AGILE.
@pjskeptic có một câu trả lời hay và @Kamil Tomšík có một nhận xét tốt về câu trả lời đó.
Điều tuyệt vời về các ngôn ngữ được gõ động như PHP là bạn có thể thử sử dụng các phương thức trên các đối tượng và nó sẽ không hét vào bạn trừ khi phương thức không có ở đó.
Vấn đề với các ngôn ngữ được gõ động như PHP là bạn có thể thử sử dụng các phương thức trên các đối tượng và nó sẽ hét vào bạn khi phương thức không có ở đó.
Các giao diện thêm một cách thuận tiện để gọi các phương thức trên một đối tượng không xác định và chắc chắn rằng các phương thức đó ở đó (không nhất thiết là chúng phải chính xác hoặc sẽ hoạt động). Nó không phải là một phần cần thiết của ngôn ngữ, nhưng nó giúp mã hóa thuận tiện hơn. Nó cho phép các nhà phát triển OOP gõ mạnh để viết mã PHP được gõ mạnh, sau đó có thể hoạt động cùng với mã PHP được gõ lỏng lẻo được viết bởi một nhà phát triển PHP khác.
một chức năng như:
foo( IBar $bar )
{
$baz = $bar->baz();
...
}
thuận tiện hơn:
foo( $bar )
{
if ( method_exists( $bar, 'baz' ) )
{
$baz = $bar->baz();
}
else
{
throw new Exception('OMGWTF NO BAZ IN BAR!');
}
...
}
và IMHO đơn giản, mã dễ đọc là mã tốt hơn.
Chúng hoàn toàn vô dụng nếu bạn là người đánh vịt, thực ra khi bạn gõ vịt, thật khó chịu khi làm việc với các thư viện / khung sử dụng bất kỳ gợi ý kiểu nào.
Điều này cũng áp dụng cho tất cả các loại lập trình meta động (phương pháp ma thuật).
PHP không phải là lỏng lẻo hoặc mạnh mẽ, nhưng được gõ động .
Về giao diện, điều đầu tiên bạn nên tự hỏi mình là: hầu hết những lợi ích của giao diện là gì?
Trong OOP, giao diện không chỉ là về các loại, mà còn về hành vi.
Vì PHP cũng có một tính năng gợi ý kiểu , bạn có thể sử dụng các giao diện giống như trong ngôn ngữ oo thuần túy, chẳng hạn như Java.
interface File
{
public function getLines();
}
CSVFile implements File
{
public function getLines()
{}
}
XMLFile implements File
{
public function getLines()
{}
}
JSONFile implements File
{
public function getLines()
{}
}
class FileReader
{
public function read(File $file)
{
foreach($file->getLines() as $line)
{
// do something
}
}
}
Với việc triển khai giao diện PHP, bạn cũng tạo các mô phỏng cho các lớp trừu tượng bằng PHPUnit - và đây là một tính năng tuyệt vời:
public function testSomething()
{
$mock = $this->getMockForAbstractClass('File');
$mock->expects($this->once())
->method('getLines')
->will($this->returnValue(array()));
// do your assertions
}
Vì vậy, về cơ bản, bạn có thể có một ứng dụng tương thích RẮN trong PHP bằng cách sử dụng các tính năng ngôn ngữ, một trong số đó là các giao diện.
Các giao diện là hữu ích cho tiêm phụ thuộc nhiều hơn so với bê tông. Như một ví dụ về barebones:
interface Istore {
public function save();
}
class Article_DB implements Istore
{
public function save($data)
{
// do save to format needed.
}
}
class Article
{
private $content;
public function content($content)
{
$this->content = $content;
}
public function save(Istore $store)
{
$store->save($this->content);
}
}
$article = new Article();
$article->content('Some content');
$store = new Article_DB();
$article->save($store);
Bây giờ nói nếu nhu cầu của bạn thay đổi và bạn muốn lưu vào pdf. Bạn có thể tạo một lớp mới cho mục đích đó thay vì làm ô nhiễm lớp Bài viết.
class Article_PDF implements Istore
{
public function save($data)
{
// do save to format needed.
}
}
$article = new Article();
$article->content('Some content');
$store = new Article_PDF();
$article->save($store);
Lớp Article hiện có một hợp đồng mà các lớp nó sử dụng để lưu phải thực hiện giao diện Istore. Nó không quan tâm nơi nó tiết kiệm hoặc làm thế nào nó tiết kiệm.
Bạn có thể cung cấp các đối tượng thực "Giả" thực hiện giao diện. Sau đó, bạn có thể kiểm tra một phần mã của mình mà không yêu cầu máy chủ thực, hệ thống tệp, ổ cắm, cơ sở dữ liệu, v.v.
Rất nhiều người có thể sẽ ghét tôi vì đã trả lời theo cách này nhưng giải pháp cho các vấn đề đánh máy của bạn có thể dễ dàng khắc phục bằng PHP. Có PHP được gõ lỏng lẻo nên các loại được mặc định giả định, điều này có thể gây ra một số vấn đề, đặc biệt là trong các hoạt động so sánh mà hầu hết mọi người đều gặp vấn đề với nó. Điều đó đang được nói, PHP có thể nghiêm ngặt như bất kỳ ngôn ngữ được gõ mạnh nào nếu bạn sử dụng những gì bạn đang sử dụng vào loại bạn cần, và sau đó sử dụng các toán tử so sánh bit. Đây là ví dụ dễ nhất tôi có thể nghĩ về những gì tôi đang nói:
$ myVar = (int) 0; $ myOtherVar = '0';
so sánh ($ myVar == $ myVar) sẽ bằng (bool) đúng
nhưng so sánh ($ myVar === $ myVar) sẽ bằng (bool) sai giống như bất kỳ so sánh "gõ" nào
Tôi thực sự chỉ mong các nhà phát triển sẽ ngừng tranh luận về những điều này, nếu bạn gặp vấn đề với cách PHP hoạt động hoặc lập trình trong java và sống và để sống, hoặc sử dụng nó theo cách nó sẽ làm những gì bạn muốn. Bitching về nó làm gì tốt cho bạn anyway? Cung cấp cho bạn một cái cớ để vít xung quanh cả ngày? Làm cho bạn trông tốt hơn so với người khác? Thật tuyệt khi bạn cảm thấy rất cao về bản thân mình rằng bạn sẵn sàng làm cho người khác xấu đi nhưng thực tế đó là sở thích của bạn và buộc niềm tin của bạn vào bất cứ ai thực sự chỉ khiến họ viết mã theo cách họ không thoải mái khi gây ra ba điều:
1) Họ sẽ mã hóa theo cách của bạn nhưng "lộn xộn" theo tiêu chuẩn của bạn (nghĩ rằng, bạn đã bao giờ thấy một lập trình viên java tạo chương trình PHP đầu tiên của họ hay ngược lại chưa? Nó sẽ giống như cách thay đổi phương pháp của họ hoặc thậm chí tệ hơn.)
2) Bạn sẽ tìm thấy một cái gì đó khác để than vãn về
3) Có thể sẽ mất nhiều thời gian hơn để họ sản xuất. Và có thể nó sẽ khiến bạn trông tốt hơn trong thời gian ngắn, nhưng toàn bộ nhóm sẽ trông tệ hơn vì điều đó (hãy nhớ rằng bạn có thể viết mã chậm hơn người khác và điều đó không hẳn là xấu miễn là nhóm đáp ứng các sản phẩm giao trong một khung thời gian hợp lý, nhưng việc ép buộc thói quen của bạn lên một người thường thực hiện nhanh hơn một chút có thể sẽ khiến cả nhóm của bạn chậm lại, do đó, trông tệ hơn trong một quy trình làm việc rất đòi hỏi)
Cá nhân tôi thích viết mã PHP theo thủ tục mặc dù tôi có thể và đã viết các chương trình đầy đủ bằng OOP bằng một vài ngôn ngữ khác nhau. Điều đó đang được nói, tôi đã thấy mã OOP tốt và mã OOP xấu, mã thủ tục tốt và mã thủ tục xấu cho vấn đề đó ... Nó thực sự không liên quan gì đến thực tiễn, nhưng với thói quen mà bạn sử dụng và thậm chí sau đó, Rất nhiều điều là cảm xúc được giải thích của tôi ... điều đó không có nghĩa là tôi sẽ nói xấu về những nhà phát triển đó hoặc nói khoe khoang với "cách của tôi là tốt nhất" BS, nó phù hợp với tôi, và công ty tôi làm việc rất tốt hạnh phúc với công việc của tôi và tôi tự hào về điều đó. Có nhiều lý do nên thiết lập một tiêu chuẩn nhưng những gì bạn đưa vào tiêu chuẩn bạn chọn là RẤT quan trọng ... Cảm ơn vì đã để tôi đưa nó ra khỏi ngực. Có một ngày tuyệt vời.
Ví dụ: Bạn cần lưu trữ dữ liệu của bạn. Làm sao? Có rất nhiều công cụ khác nhau để lưu vào bộ đệm, cái nào là tốt nhất? Ai quan tâm nếu bạn có lớp trừu tượng có giao diện ICacheDriver với một tập hợp các phương thức như key, get, put, Clear, v.v. Chỉ cần thực hiện cho nó những gì bạn cần trong dự án hiện tại và thay đổi nó khi bạn cần một phương thức khác. Hoặc sử dụng đơn giản của toString. Bạn có một bộ các đối tượng hiển thị khác nhau. Bạn chỉ cần thực hiện giao diện Stringable (mô tả phương thức toString [không có giao diện thực sự như trong PHP, nhưng chẳng hạn]) và chỉ giao thoa trên tất cả các đối tượng của bạn với (chuỗi) $ obj. Có tất cả những gì bạn cần làm thay vì chuyển đổi (true) {case $ obj isntanceof A1: "do 1"; phá vỡ; ...}
Đơn giản. Vì vậy, không có câu hỏi "Tại sao?". Có "làm thế nào để sử dụng tốt hơn?". ;-) Chúc may mắn.
Tôi đoán.
PHP được sử dụng bởi nhiều lập trình viên cấp đầu vào, lập trình viên cấp nhập cảnh được dạy java ở trường đại học.
Sau khóa học Lập trình 101, họ bắt đầu cằn nhằn Zend, họ muốn có các tính năng java bởi vì đó là cách họ được dạy để suy nghĩ, suy nghĩ theo cách riêng của bạn (hoặc hiểu cách gõ vịt) thật khó, khi bạn chỉ mới 20 tuổi.
Zend rất thực dụng, việc thêm tính năng này sẽ dễ dàng hơn là giả vờ chúng ở đâu cũng đúng.
Điều này cũng mua ở nhiều người dùng hơn thay vì khiến họ rời đi, vì vậy nó phải tốt.
Một ví dụ khác của quá trình này? Mọi người mới ra khỏi các khóa học .NET và Java cũng muốn các Khung công tác lớp , họ cằn nhằn về điều đó cho đến khi Zend nảy ra Khung công tác Zend . Điều này mua ở nhiều người dùng hơn. Và trên và trên ...
(tính năng ngôn ngữ duy nhất mà nhóm PHP được biết là đã đấu tranh chống lại , trong nhiều năm qua, là goto
)
PHP12
có lẽ sẽ có tất cả các tính năng cú pháp của thế giới (tôi hy vọng nó không có thời gian chạy lớp trừu tượng, khó khăn, vì đó là thứ đã giết chết perl) với một cái nháy mắt cho các mô hình chức năng và kiểu dữ liệu, nhưng vẫn không có goto
.