一、类扩展(继承),抽象,接口
属性重载
__get(), __set()
<?php
namespace _0815;
/////////////demo1//////////////
/**
* 属性重载 __get(),__set()
*
*/
//封装,重载,继承
class User
{
//private:私有封装
private array $data = [
'age' => 20,
];
//查询接口
public function __get($name)
{
$condition = array_key_exists($name, $this->data) ;
return $condition ? $this->data[$name] : "$name 属性不存在";
}
//设置接口
public function __set($name, $value)
{
$condition = array_key_exists($name, $this->data) ;
if(!$condition){
//这里如果不做提示和返回,对于把age错写成ag3,echo时又写对成age,是不是不好定位设置值不成功的问题?
echo "$name 属性不存在<br>";
// 但是这里出现了多处返回,是不是部分编辑器会报错?
return ;
}
return $condition ? $this->data[$name] : "$name 属性不存在";
}
}
$user =new User();
echo $user->age.'<br>';
$user->ag3 = 10;
echo $user->age.'<br>';
遗留问题:
如上述代码注释所述,array_key_exist在__set中应用,多处return是否可以?不可以,如何处理注释中提到的问题?
方法重载
__call(), static function __callStatic()
<?php
namespace _0815;
/////////////demo1//////////////
/**
* 属性重载 __get(),__set()
* 方法重载 __call($name, $args), __callStatic($name, $args)
*/
//封装,重载,继承
class User
{
//private:私有封装
private array $data = [
'age' => 20,
];
//查询接口
public function __get($name)
{
$condition = array_key_exists($name, $this->data) ;
return $condition ? $this->data[$name] : "$name 属性不存在";
}
//设置接口
public function __set($name, $value)
{
$condition = array_key_exists($name, $this->data) ;
if(!$condition){
//这里如果不做提示和返回,对于把age错写成ag3,echo时又写对成age,是不是不好定位设置值不成功的问题?
echo "$name 属性不存在<br>";
// 但是这里出现了多处返回,是不是部分编辑器会报错?
return ;
}
return $condition ? $this->data[$name] : "$name 属性不存在";
}
// 可以自动拦截对方法的非法请求
public function __call($name, $arguments)
{
printf('非法动态方法:%s,<pre>%s</pre>.<br>', $name, print_r($arguments, true));
}
// 拦截对静态方法的非法请求
public static function __callStatic($name, $arguments)
{
printf('非法静态方法:%s,<pre>%s</pre>.<br>', $name, print_r($arguments, true));
}
}
$user =new User();
echo $user->age.'<br>';
$user->ag3 = 10;
echo $user->age.'<br>';
// 非静态方法
$user->hello('路人甲','4352259');
// 静态方法
User::world('路人乙','28375985');
THINKPHP查询构造器模拟
//ThinkPHP,查询构造器,数据库操作
class Query
{
public function table()
{
echo 'Query table()->';
return $this;
}
public function where()
{
echo 'Query where()->';
return $this;
}
public function find()
{
echo 'Query find()<br>';
}
}
// 查询入口
class Db
{
//实例化时自动连接数据库
// public function __construct()
// {
// self::connect();
// }
public static function __callStatic($name, $arguments)
{
// printf('方法:%s,参数:<pre>%s</pre>',$name, print_r($arguments, true));
// 所有查询在此完成,单入口查询
return call_user_func_array([new Query, $name] , $arguments);
}
}
Db::table('think_user')->where('id', 1)->find();
类扩展(继承)
/**
* 类的扩展(继承)/抽象/最终
* 1. 可继承成员protected
* 2. extends: 类成员的来源
* 3. parent:父类引用
*/
class Person
{
//属性
// public:公共成员,类内、子类、类外部可访问
public string $email = 'admin@php.cn';
// private:私有成员,类内可访问。
private int $id = 10;
//protected:受保护成员,类内、子类可访问。
protected string $name;
//方法
public function __construct($name)
{
$this->name =$name;
}
// 自定义方法
protected function getInfo():string
{
return $this->name;
}
}
class Stu extends Person
{
//只需要扩展属性和方法
// 属性扩展
private string $lesson;
private int $score;
//方法扩展
// 构造方法扩展
public function __construct($name, $lesson, $score)
{
//引用父类
parent::__construct($name);
$this->lesson = $lesson;
$this->score =$score;
}
// 为方便外部访问,由public定义
public function getInfo(): string
{
return parent::getInfo().'同学,'.$this->lesson.'成绩:'.$this->score.'<br>';
}
}
$stu = new Stu('路人甲', 'php', 99);
echo $stu->getInfo();
抽象类
// 禁用父类,仅允许通过他的子类来访问父类成员。
// 把当前类声明为抽象类abstract。
// 如果类中有抽象方法,则必须声明为抽象类。
abstract class demo1
{
public string $name = 'admin';
// 抽象方法,没有具体实现体的方法应该声明成抽象方法。
abstract public static function getInfo($name);
}
class demo2 extends demo1
{
// 在子类中必须实现父类抽象方法,否则报错。
public static function getInfo($name)
{
return 'Hello,'.$name;
}
}
echo demo2::getInfo('路人甲');
最终类
// final最终类,禁止继承,直接用
final class demofin
{
}
//继承会报错
class demo extends demofin
{
}
接口
//接口:升级版的抽象类
interface iUser
{
//接口的属性必须是常量
public const NATION = 'CHINA';
//接口方法必须是public
public function m1();
public function m2();
}
// 工作类:实现接口内容
class demo1 implements iUser
{
// 接口中的抽象方法必须在工作类中全部实现
public function m1()
{
}
public function m2()
{
}
}
// 仅实现一部分,需声明为抽象子类
abstract class Demo2 implements iUser
{
public function m1()
{
}
}
class demo3 extends Demo2
{
public function m2()
{
}
}
// php是单继承,可以通过接口间接多继承,不推荐
interface A
{
}
interface B
{
}
interface C
{
}
// 多继承
class Test implements A, B, C
{
}
interface iDb
{
// 插入
public static function insert(array $data);
// 更新
public static function update(array $data, string $where);
// 删除
public static function delete(string $where);
// 查询
public static function select(array $options);
}
//这个地方上课时没有implements,是默认的么?
abstract class aDb implements iDb
{
// 插入
public static function insert(array $data)
{
}
// 更新
public static function update(array $data, string $where)
{
}
// 删除
public static function delete(string $where)
{
}
// 查询
public static function select(array $options)
{
}
}
class Db extends aDb
{
}
二、全局成员和命名空间
全局成员
全局成员:函数,常量,类/接口,全局有效,禁止重复声明
命名空间
作用
解决全局成员命名冲突问题
声明
namespace _0815;
function hello()
{
}
const A = 1;
class D
{
}
namespace _0815_1;
function hello()
{
}
const A = 1;
class D
{
}
跨空间访问
namespace one;
class Demo1
{
public static string $name = 'admin';
}
// 当存在命名空间时,全局成员应该使用完整名称。
// 完整类名 = 空间名称\类名
// ::class 获取完整类名
echo Demo1::class.'<br>';
namespace two;
class demo1
{
public static string $name = '路人甲';
}
echo Demo1::class.'<br>';
// 跨空间访问
// echo one\Demo1::$name;->实际访问’two\one\Demo1‘
// 要从根空间'\'开始
echo \one\Demo1::$name;
命名空间的类型
// 1. 当前路径:非限定名称 Index
// 2. 相对路径:限定名称 two\Index
// 3. 绝对路径:完全限定名称 \one\two\Index
namespace _0815;
namespace one;
class index
{
public static function show()
{
return __METHOD__;
}
}
echo Index::show().'<br>';
echo two\Index::show().'<br>';
// 空间可分层
namespace one\two;
class index
{
public static function show()
{
return __METHOD__;
}
}
echo Index::show().'<br>';
命名冲突
use起别名简化长度
namespace one;
class Index
{
public static function show()
{
return __METHOD__;
}
}
echo \one\two\three\Index::show().'<br>';
// use默认使用完全限定名称的类名/绝对路径,用别名简化长度。
use \one\two\three\Index as UserIndex;
echo UserIndex::show().'<br>';
//-----------------------------------------
namespace one\two\three;
class Index
{
public static function show()
{
return __METHOD__;
}
}
上面代码中,如果namespace one没有Index类,那么use可以直接起别名Index,
...
use \one\two\three\Index as Index;
echo Index::show().'<br>';
当前类别名Index与原始类名相同,还可以不写
...
use \one\two\three\Index;
echo Index::show().'<br>';