PHP 抽象类和方法
何时可以使用abstract关键字定义类抽象。定义为抽象的类无法实例化。
以下是关于抽象类和方法的一些重要观点:
- 抽象类可以像任何其他普通类一样拥有方法和属性。
- 抽象类无法实例化,因此我们需要创建一个扩展它的子类,然后我们可以创建子类的对象。
- 如果一个类甚至只有一个抽象方法,那么该类也应该是抽象的。
- 抽象方法只是声明,我们提供方法和参数的名称,而正文部分是空的。
不要担心,如果它将太多了你不明白。我们将通过示例逐步介绍所有要点,让我们从了解如何创建抽象类开始。
创建一个abstract类
要声明类抽象,我们需要abstract在类的名称之前使用关键字。
我们来举个例子:
1 2 3 4 5 6 7 8 9 10 11 | <?php // abstract class abstract class Vehicle { // abstract function mileage abstract public function mileage() { } } ?> |
在上面的例子中,我们的类Vehicle
是一个抽象类,它有一个抽象方法。
创建抽象类的想法是绑定开发人员遵循一组准则,例如,如果你想创建一个扩展我们的类的新类,Vehicle
那么你将不得不提供抽象方法的定义mileage()
,否则子类也应该是抽象的。因此,所有子类都必须提供该方法的定义mileage()
。
抽象类中的非抽象方法
任何具有单个抽象方法的类都必须声明为abstract。但是抽象类也可以有非抽象方法,可以由子类直接访问和使用,而不会覆盖它们。
让我们扩展上面的例子,并在我们的类中包含一个非抽象的方法Vehicle:
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 29 | <?php // abstract class abstract class Vehicle { // protected variable protected $name; // non-abstract public function start public function start() { echo $this->name. " - Engine start...<br/>"; } // non-abstract public function stop public function stop() { echo $this->name. " - Engine stop...<br/>"; } // non-abstract public function setName public function setName($name) { $this->name = $name; } // abstract function mileage abstract public function mileage() { } } ?> |
在上面的代码,我们增加了三个非抽象方法,即start()
,stop()
和setName()
我们的抽象Vehicle
类。
继承抽象类
就像任何其他类一样,我们也可以创建扩展抽象类的类。
这里唯一的区别是子类必须为抽象父类中声明的抽象方法提供定义。
如果子类没有为抽象方法提供定义,那么它也应该被定义为抽象类。
让我们创建两个继承该类的子类Vehicle,它们将具有抽象方法的定义mileage():
1 2 3 4 5 6 7 8 9 10 11 12 | <?php // child class class Car extends Vehicle { public function mileage() { echo "I am " . $this->name . "<br/>"; echo "My mileage range is - 15 to 22 Km/L"; } } ?> |
我们可以拥有任意数量的子类,让我们有另一个类:
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php // child class class Motorcycle extends Vehicle { public function mileage() { echo "I am " . $this->name . "<br/>"; echo "My mileage range is - 35 to 47 Km/L"; } } ?> |
如上所述,抽象类不能有任何对象,一旦我们定义了适当的子类,我们就可以为它们创建对象。
1 2 3 4 5 6 7 | <?php $car = new Car(); $car->setName("BMW X1"); $car->mileage(); ?> |
输出
1 2 | I am BMW X1 My mileage range is - 15 to 22 Km/L |
如果你想尝试,继续尝试创建类的对象Vehicle
,你将收到一个错误。
PHP 接口(Interfaces)
就像抽象类一样,也创建了接口来定义继承接口的类的蓝图。接口没有抽象方法,但public
没有定义的方法,继承接口的类必须为接口内声明的方法提供定义。
定义PHP接口的语法
类似于使用关键字定义的类class
,接口是使用关键字interface
后跟接口名称定义的。
1 2 3 4 5 6 7 | <?php // interface declaration interface NameOfInterface { } ?> |
并且类使用implements
关键字从接口继承并实现接口中声明的方法。
1 2 3 4 5 6 7 | <?php // class declaration class SomeClass implements NameOfInterface { } ?> |
让我们举一个简单的例子,我们将创建一个接口,其中包含一些声明的接口,并且实现它的类将被绑定为这些方法提供定义。
以下是我们的界面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <?php // interface declaration interface WebApp { // methods declaration public function login($email, $password); public function register($email, $password, $username); public function logout(); } ?> |
我们定义的名称的接口WebApp
,其中有声明,即三个抽象方法login()
,register()
和logout()
。正如您在上面的代码中看到的,我们还提供了方法将接受的参数。
现在让我们创建一个实现上述接口的类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php // class declaration class Sky8g implements WebApp { // methods definition public function login($email, $password) { echo "Login the user with email: " . $email; } public function register($email, $password, $username) { echo "User registered: Email=".$email." and Username=".$username; } public function logout() { echo "User logged out!"; } } ?> |
在上面的类中,我们实现了接口WebApp并为接口中声明的所有方法提供了定义。
实现多接口
一个类也可以实现多个接口。在这种情况下,类必须为类实现的所有接口中声明的方法提供定义。
让我们创建另一个界面:
1 2 3 4 5 6 7 8 9 10 | <?php // interface declaration interface CMS { // methods declaration public function publishPost($post); } ?> |
现在让我们将上面的接口添加到我们的类Sky8g
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?php // class declaration class Sky8g implements WebApp, CMS { // methods definition public function login($email, $password) { echo "Login the user with email: " . $email; } public function register($email, $password, $username) { echo "User registered: Email=".$email." and Username=".$username; } public function logout() { echo "User logged out!"; } public function publishPost($post) { echo $post." published!"; } } ?> |
现在我们的类Sky8g实现了两个接口。
需要注意的一些要点:
- 接口中声明的所有方法都是
public
以abstract
关键字开头的。 - 如果我们错过了实现接口中声明的单个方法,那么在实现接口的类中,我们将得到一个错误。
- 接口没有变量。
不要担心,如果它太多了你不明白。我们将通过示例逐步介绍所有要点,让我们从了解如何创建抽象类开始。
abstract类和接口之间的区别
以下是抽象类和接口之间的一些重要区别:
接口(Interface) | 抽象类(Abstract Class) |
接口不能有具体的方法,即带有定义的方法。 | 抽象类可以包含abstract 方法和具体方法。 |
接口中声明的所有方法都应该是 public | 抽象类可以有public ,private 和protected 等方法。 |
多个接口可以由一个类实现。 | 一个类只能扩展一个抽象类。 |
PHP 错误处理
在我们学习如何处理PHP中的错误之前,我们首先应该知道什么是错误。
一个错误据说已经发生时的一段代码返回意想不到的结果或突然停止由于例如某些不正确的代码被零除,或无限循环等。
在PHP中,我们可以设置PHP配置以在浏览器中显示错误消息或隐藏它们。
PHP提供了多种处理错误的方法.
- 使用条件语句或die()函数处理代码中的错误
- 使用自定义错误处理程序
- PHP错误报告
让我们用例子来介绍它们。
使用die()功能
die()
是PHP中的函数用于显示任何消息并同时退出当前脚本。因此,一旦检测到错误条件,die()
就可以使用函数来退出代码执行。
当我们尝试将数字除以零或者尝试打开不存在的文件时,可能会发生错误,让我们举个例子,看看我们如何使用die()
函数或条件语句来处理错误条件。
1 2 3 4 5 6 7 8 | <?php $fileName = "noerror.txt"; // opening the file fopen($fileName, "r") or die("Unable to open file $fileName"); ?> |
在上面的代码片段中,如果在给定位置没有名称为noerror.txt
的文件,我们将在屏幕上显示无法打开文件noerror.txt
的消息。
该die()
函数是函数exit()
的别名,exit()
也用于退出代码执行。
现在让我们看看如何使用条件语句来处理错误情况。当我们知道可能导致错误的情况时,这种类型的错误处理很有用。
例如,以下代码将导致错误:
1 2 3 4 5 6 7 8 9 10 11 | <?php function division($numerator, $denominator) { // perform division operation echo $numerator / $denominator; } // calling the function division(7, 0); ?> |
输出
1 | Warning: Division by zero... |
在这种情况下,我们知道某些条件会导致错误,我们可以使用条件语句来处理会导致错误的极端情况。我们来修复上面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php function division($numerator, $denominator) { // use if statement to check for zero if($denominator != 0) { echo $numerator / $denominator; } else { echo "Division by zero(0) no allowed!"; } } // calling the function division(7, 0); ?> |
输出
1 | Division by zero(0) no allowed! |
正如您在上面的代码中看到的那样,处理错误条件。现在我们的代码不会在scree
上显示任何错误,而是会显示一条消息并正常退出。
使用自定义错误处理程序
在PHP中,我们可以使用自定义方法显示任何消息或在发生错误时执行任何代码。我们所要做的就是使用该函数将我们的方法设置为PHP 的默认错误处理程序set_error_handler()
我们来举个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?php // custom function to handle error function sky8g_error_handler($error_no, $error_msg) { echo "Oops! Something unexpected happen..."; echo "Possible reason: " . $error_msg; echo "We are working on it."; } // set the above function s default error handler set_error_handler("sky8g_error_handler"); $result = 7 / 0; ?> |
输出
1 2 3 | Oops! Something unexpected happen... Possible reason: Division by zero We are working on it. |
我们可以像上面用参数一样定义自己的函数$error_no
,$error_msg
并且可以根据需要处理它们。我们可以在数据库中显示自定义消息,日志错误,向报告错误的开发人员发送电子邮件等。
PHP错误报告
PHP提供默认的错误报告机制,可用于在发生错误时在屏幕上显示消息。
执行错误处理以优雅地处理代码中的错误并为最终用户提供更好的用户体验。
我们可以使用PHP函数error_reporting()来设置要显示的错误以及要隐藏的错误。
以下是此函数的语法:
1 2 3 4 5 | <?php // error reporting function error_reporting($reporting_level); ?> |
变量的值$reporting_level
定义要显示的错误以及要隐藏的错误,如果我们不为其提供任何值,则错误报告将设置为默认值。
以下是我们可以提供的用于设置各种错误级别的值:
报告级别 | 描述 |
E_WARNING | 仅显示警告消息,并且不会停止脚本的执行。 |
E_NOTICE | 显示正常代码执行期间发生的通知。 |
E_USER_ERROR | 显示用户生成的错误,即自定义错误处理程序。 |
E_USER_WARNING | 显示用户生成的警告消息。 |
E_USER_NOTICE | 显示用户生成的通知。 |
E_RECOVERABLE_ERROR | 显示非致命错误。 |
E_ALL | 显示所有错误和警告。 |
这使我们得出PHP中错误处理的结论。在下面一个教程中,我们将了解异常处理。
PHP 异常处理
在上一个教程中,我们介绍了错误处理。现在问题出现了,Exception
和Error
之间有什么区别。
PHP引入了一种新的面向对象的处理错误的方法,称为异常(Exception)。
异常处理用于处理错误并在代码执行过程中重定向,而不像代码执行停止并且屏幕上显示错误消息的错误。
使用try和catch阻止
可以导致异常或错误的代码包含在try
块中,如果没有异常发生,则代码正常执行,而在异常的情况下,代码执行退出try块并进入catch
块。
以下是使用try
和catch
进行异常处理的语法,
1 2 3 4 5 6 7 8 9 10 | <?php try { //code goes here that could lead to an exception } catch (Exception $e) { //exception handling code goes here } ?> |
throw Exception
如果需要,我们可以使用关键字手动触发异常throw。Exception是一个PHP类,它是PHP中所有异常类的父类。
要抛出异常,我们必须创建异常类的对象,然后使用该throw关键字来触发该异常。
我们来举个例子:
1 2 3 4 5 6 7 8 | <?php // funciton declaration function triggerException() { // using throw keyword throw new Exception("Manually triggering exception..."); } ?> |
如果我们调用上面的函数,triggerException()
那么它将抛出异常。
现在我们可以在一个try
块中调用这个函数并处理块中的异常catch()
,如下所示:
1 2 3 4 5 6 7 8 9 10 11 | <?php try { // calling the function triggerException(); } catch (Exception $e) { echo "Oops! Some unexpected error occured..."; } ?> |
输出
1 | Oops! Some unexpected error occured... |
在catch
块内部,我们还可以使用该getMessage()
方法从异常对象中获取消息。
自定义异常类
我们可以通过扩展ExceptionPHP
提供的类来创建自定义异常类。
下面我们有一个自定义异常类的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <?php // custom exception class class Sky8gException extends Exception { // define constructor function __construct() { // we can even take arguments if we want } // we can define class methods if required } ?> |
当您需要自定义错误处理时,自定义异常类很有用,例如数据库中的日志记录错误等。
处理多个异常
如果一段代码可以抛出不同类型的异常,并且基于异常类型我们必须执行某些操作,在这种情况下我们可以有多个catch
块:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <?php try { // calling the function triggerException(); } catch (Sky8gException $e) { // do something here... } catch (Exception $e) { echo "Oops! Some unexpected error occured..."; } ?> |
使用多个catch
块处理多个异常时要记住的几个要点:
catch
块处理子类的Exception
类必须放在catch
处理Exception
类的块之上。或者换句话说,应该保留Exception
类处理catch
块。catch
处理Exception
类的块也可以处理其他的excpetions
,因为所有的异类都是class
的子Exception
类。
下一章我们将介绍:PHP 高级教程-面向对象编程(OOP)[第四章]