- interface中的方法都是抽象方法,抽象方法用public修饰。抽象方法就是没有方法体的方法。
- interface中的属性只能是常量,不能为变量。
- 类实现interface时使用关键字implements来实现。
- 由于interface不是一个‘类’(不是class),所以肯定不能被实例化
- interface可以继承interface,使用extends继承。因为interface里面的方法全是抽象方法,所以只能继承interface,而不能继承class等,class类中的方法都是有方法体的。
- 类是单继承的,但类是可以实现多个接口,使用逗号分割。
interface demo {
const NAME = "常量对象属性";
function fun1();
function fun2(); //抽象方法。
}
class MyPc extends Root implements demo , demo2 , demo3 {
...
}
- 实现了interface的类必须
全部重写
interface中的所有抽象方法。如果一个类实现了一个接口,且该接口继承了某个父接口,那么这个类要实现这俩个接口的所有抽象方法。 - interface中的方法应该表明return的类型,方便在用户在实现接口时返回相应的结果
interface顾名思义就是接口,接口里面的抽象方法需要用户自己实现的,为什么要用户实现呢?因为这些方法内的逻辑因人而异,所以方法内的具体代码逻辑交由用户自己操作。依赖注入容器就是一个很常见的interface,遵循PSR-11规范
总结:当方法内的逻辑需要用户自己去实现时,我们就可以使用接口。实现了某interface的类可以注入到该interface类型的类中。
举个例子。比如有一个数据库操作的interface,需要用户来实现接口内的查询,删除等方法。因为我们不知道用户到底用哪种数据库驱动,所以将所有操作交给用户自己实现
- 一个DbInterface接口
<?php
namespace App\learn;
interface DbInterface{
public function add($key,$value);
public function delete($key);
public function query($key);
public function update($key,$value);
}
- 实现DbInterface接口
<?php
use App\learn\DbInterface;
class RedisDb implements DbInterface
{
public $connection;
public function __construct()
{
$this->connection=new Redis('127.0.0.1',6379);
}
public function add($key,$value)
{
$status= $this->connection->set($key,$value);
return $status;
}
public function delete($key)
{
$status=$this->connection->del($key);
return $status;
}
public function update($key,$value)
{
$status=$this->connection->set($key,$value);
return $status;
}
public function query($key)
{
$status=$this->connection->get($key);
return $status;
}
}
- 类需要依赖注入DbInterface依赖,该依赖可以是一个实现了DbInterface的接口的类
这里必须是注入DbInterface依赖,可能有人问为什么不直接注入RedisDb依赖呢?因为RedisDb类是用户自己定义的实现interface的类,用户A可能是RedisDb,用户B可能是mysqlDb,因为我们并不知道用户定义的类叫啥,所以这里要依赖注入DbInterface。
<?php
use App\learn\DbInterface;
class School
{
public $db;
//注入一个DbInterface依赖,该依赖可以是一个实现了DbInterface的接口的类。
public function __construct(DbInterface $db)
{
$this->db = $db;
}
public function addClass($className,$num)
{
return $this->db->add($className,$num);
}
public function showClass($className)
{
return $this->db->query($className);
}
}
- 实例化School类
$school=new School(new \RedisDb());
$status=$school->addClass('082班',63);
以上就是接口的常用方法。
在举一个常见的例子,接口和工厂模式的结合。
应用场景:连接数据库,可以使用mysql 、mysqli、pdo,根据不同参数配置使用不同的数据库操作类。
为了统一操作类实现的方法,所以我们定义一个接口,然后这些数据库操作类都实现这个接口。
最后使用工厂模式中根据传入的参数来决定使用哪种数据库驱动
/**
* 抽象产品(共同接口)
* @定义一个工厂接口
*/
interface mysql{
public function connect();
}
/**
* Class mysqli2
* 具体产品实现
* @实现这个接口
*/
class mysqli implements mysql{
public function connect(){
echo 'mysqli';
}
}
/**
* Class pdo2
* 具体产品实现
* @实现这个接口
*/
class pdo implements mysql{
public function connect(){
echo 'pdo';
}
}
/**
* Class mysqlFactory
* 通过传入不同的参数来实例化不同的对象;统一在工厂类中进行实例化
*/
class mysqlFactory{
static public function factory($class_name){
return new $class_name();
}
}
$obj = mysqlFactory::factory('pdo');
$obj->connect();
interface,trait和class的结合
上面说实现了interface的class必须全部重写
interface中的抽象方法。
现在还有另一种方式:继承了interface的class可以不用实现interface中的抽象方法,而抽象方法交给trait实现,然后class中use该trait即可。
具体实现如下:
- 定义一个接口
<?php
namespace App\learn;
interface UserInterface
{
public const SEX=1;
public function birthday($old);
public function position($status);
}
- 实现一个trait
<?php
namespace App\learn;
trait UserTrait
{
public function birthday($old)
{
return $old;
}
public function position($status)
{
return $status;
}
}
- 定义一个实现了UserInterface接口的类
由于此类use了一个UserTrait,而该trait内已经实现了接口中的所有抽象方法,所以此类不需要在重写接口中的所有抽象方法了。
这种方式是经常能够看到的。
<?php
namespace App\learn;
class School implements UserInterface
{
use UserTrait;
}
网友评论