一、trait
http://php.net/manual/zh/language.oop5.traits.php
应用的几个 Class 之间不需要继承
自己的理解 trait 不需要去继承 指需在需要用到它的类里面 use 其名称即可,同时须在 class 上方use 完整地址如下
<?php
namespace app\customer\model;
use app\manager\model\Staff;
use app\oa\relation\Commentable;
use think\Model;
use think\model\concern\SoftDelete;
/**
* @property integer $id
*/
class Reimbursement extends Model
{
use SoftDelete,Commentable;
const SUCCESS = 654; //已完成
const PENDING = 655; //待处理
const PROCESSING = 661; //处理中
const CHECK = 662; //待审核
const SETTLED = 663; //待结算
const DISMISSED = 664; //已驳回
const REJECT = 690; //已拒绝
protected $name = 'reimbursement';
protected $type = [
'album' => 'json',
'payment_pic' => 'json',
'reimbursement' => 'json'
];
/**
* @param array $data 新增
* @return false|int
*/
public function store($data)
{
return $this->isUpdate(false)->allowField(true)->save($data);
}
/**
* @param array $data 修改
* @return false|int
*/
public function edit($data)
{
return $this->isUpdate(true)->allowField(true)->save($data);
}
public function results()
{
return $this->hasOne(ReimbursementResult::class,'reimbursement_id');
}
public function staffs()
{
return $this->hasOne(Staff::class,'id','staff_id')->field('id,real_name');
}
public function getTypeAttr($raw)
{
$segments = explode(',', $raw);
$result = [];
foreach ($segments as $segment) {
$result[] = ['id' => $segment, 'dictionary_name' =>array_get(app('dict'), $segment)];
}
return $result;
}
}
从基类继承的成员会被 trait 插入的成员所覆盖。优先顺序是来自当前类的成员覆盖了 trait 的方法,而 trait 则覆盖了被继承的方法。
abstract
http://php.net/manual/zh/language.oop5.abstract.php
抽象类【定义为抽象的类不能被实例化,如果一个类里面有抽象方法,那么这个类就必须声明为抽象类,被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。】
<?php
abstract class AbstractClass
{
// 强制要求子类定义这些方法
abstract protected function getValue();
abstract protected function prefixValue($prefix);
// 普通方法(非抽象方法)
public function printOut() {
print $this->getValue() . "\n";
}
}
class ConcreteClass1 extends AbstractClass
{
protected function getValue() {
return "ConcreteClass1";
}
public function prefixValue($prefix) {
return "{$prefix}ConcreteClass1";
}
}
class ConcreteClass2 extends AbstractClass
{
public function getValue() {
return "ConcreteClass2";
}
public function prefixValue($prefix) {
return "{$prefix}ConcreteClass2";
}
}
$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue('FOO_') ."\n";
$class2 = new ConcreteClass2;
$class2->printOut();
echo $class2->prefixValue('FOO_') ."\n";
?>
返回数据
ConcreteClass1
FOO_ConcreteClass1
ConcreteClass2
FOO_ConcreteClass2
对象接口
interface 【使用接口(interface),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容,接口是通过 interface 关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的。接口中定义的所有方法都必须是公有,这是接口的特性。】
implements 【实现接口】【实现多个接口时,接口中的方法不能有重名、接口也可以继承,通过使用 extends 操作符、类要实现接口,必须使用和接口中所定义的方法完全一致的方式。否则会导致致命错误。】
Final 关键字
新增了一个 final 关键字。如果父类中的方法被声明为 final,则子类无法覆盖该方法。如果一个类被声明为 final,则不能被继承。
异常处理
<?php
function inverse($x) {
if (!$x) {
throw new Exception('Division by zero.');
}
return 1/$x;
}
try {
echo inverse(5) . "\n";
echo inverse(0) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
// Continue execution
echo "Hello World\n";
?>
返回数据
0.2
Caught exception: Division by zero.
Hello World
加finally 的异常处理
<?php
function inverse($x) {
if (!$x) {
throw new Exception('Division by zero.');
}
return 1/$x;
}
try {
echo inverse(5) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
} finally {
echo "First finally.\n";
}
try {
echo inverse(0) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
} finally {
echo "Second finally.\n";
}
// Continue execution
echo "Hello World\n";
?>
返回数据
0.2
First finally.
Caught exception: Division by zero.
Second finally.
Hello World
抛出异常
<?php
class MyException extends Exception { }
class Test {
public function testing() {
try {
try {
throw new MyException('foo!');
} catch (MyException $e) {
// rethrow it
throw $e;
}
} catch (Exception $e) {
var_dump($e->getMessage());
}
}
}
$foo = new Test;
$foo->testing();
?>
以上会输出
string(4) "foo!"
static 【后期静态绑定】 self 【当前调用】
http://php.net/manual/zh/language.oop5.late-static-bindings.php
self:: 的限制
使用 self:: 或者 __CLASS__ 对当前类的静态引用,取决于定义当前方法所在的类:
self:: 用法
<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
self::who();
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
?>
以上会输出
A
static:: 简单用法
<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
static::who(); // 后期静态绑定从这里开始
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
?>
以上会输出
B
后期静态绑定的解析会一直到取得一个完全解析了的静态调用为止。另一方面,如果静态调用使用 parent:: 或者 self:: 将转发调用信息。
<?php
class A {
public static function foo() {
static::who();
}
public static function who() {
echo __CLASS__."\n";
}
}
class B extends A {
public static function test() {
A::foo();
parent::foo();
self::foo();
}
public static function who() {
echo __CLASS__."\n";
}
}
class C extends B {
public static function who() {
echo __CLASS__."\n";
}
}
C::test();
?>
以上会输出
A
C
C