Correcting teacher:PHPz
Correction status:qualified
Teacher's comments:
__get()
,__set()
__call()
,__callStatic()
// 查询拦截器
public function __get($name)
{
// $name : 属性名
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}
return "属性 {$name} 不存在";
}
// 更新拦截器
public function __set($name, $value)
{
// 1. 有没有这个属性?
if (array_key_exists($name, $this->data)) {
// 2. 这个值是否合法?
if ($name === 'age') {
if ($value >= 18 && $value <= 59) {
$this->data[$name] = $value;
} else {
echo '年龄必须在18-59之间';
}
} else {
// 以上操作仅对age有效,其它属性直接赋值
$this->data[$name] = $value;
}
} else {
echo '禁止动态创建属性';
}
}
// 方法拦截器
public function __call($name, $args)
{
// $name: 方法名, $args: 传给方法的参数
printf('方法: %s<br>参数:<pre>%s</pre>', $name, print_r($args, true));
}
// 静态方法拦截器
public static function __callStatic($name, $args)
{
// $name: 方法名, $args: 传给方法的参数
printf('方法: %s<br>参数:<pre>%s</pre>', $name, print_r($args, true));
}
<?php
// 方法重载的小案例
// Db::table('think_user')->where('id', 1)->find();
// 1. 查询类
class Query
{
public function table($table)
{
// 返回当前类实例,方便后面的链式调用
return $this;
}
public function where($where)
{
return $this;
}
public function find()
{
// 不需要返回 $this,它最一个最终方法,输出查询结果
// 用数组来模拟数据表的查询结果
return ['id' => 1, 'name' => '猪老师', 'email' => '498668472@qq.com'];
}
}
$query = new Query;
// $query->table('think_user');
// $query->where('id', 1);
// $query->find();
$query->table('think_user')->where('id', 1)->find();
// Db::table('think_user')->where('id', 1)->find()
// 2. 入口类: 实现请求转发
class Db
{
// 静态方法重载/重定向
public static function __callStatic($name, $args)
{
// $query = new Query;
// return $query->$name($args);
// 回调的方式来执行对象方法
return call_user_func_array([new Query, $name], $args);
}
}
$res = Db::table('think_user')->where('id', 1)->find();
printf('<pre>%s</pre>', print_r($res, true));
命名空间,解决了全局成员的命名冲突
全局成员:类/接口,常量,函数
function hello(){}
const APP = '社区';
class Demo1{}
interface A{}
命令空间类型
// 一个脚本中,可以创建多个空间
namespace ns1 {
// 空间成员
//常量
const APP = '商城';
}
// 子空间要写在父空间的上面,这样才能在父空间里面访问
// 空间分级管理: 子空间
namespace ns2\ns3 {
const APP = '问答';
echo APP . '<br>';
}
namespace ns2 {
// 空间成员
// 常量
const APP = '社区';
// 2. 非限定名称: 总是从当前空间开始查询
echo APP . '<br>';//直接访问即可
echo \ns2\APP . '<br>'; //也可以用这种方式
// 在ns2中访问 ns1的APP
// 一定要通过全局空间/根空间进行访问
// 根空间: \
// 1. 完全限定名称: 从根空间开始查询
echo \ns1\APP . '<br>';
// 在ns2空间, 访问子空间 ns2\ns3中的成员
// 3. 限定名称: ns3\APP,因为已经在ns2里面了,所以不需要写ns2
echo '<span style="color:red">' . ns3\APP . '</span><br>';
}
namespace {
function hello()
{
echo 'hello 大家好';
}
//访问ns1空间内的APP
echo '<span style="color:blue">' . ns1\APP . '</span><br>';
//访问ns3里面的APP
echo '<span style="color:coral">' . \ns2\ns3\APP . '</span><br>';
}
做个类文件自动加载器来加载类
// 类文件自动加载器
// 注册一个类的自动加载器
spl_autoload_register(function ($class) {
// echo $class;
// 1. 将命名空间=>映射到一个类文件的绝对路径
$path = str_replace('\\', DIRECTORY_SEPARATOR, $class);
// 2. 生成类文件路径
$file = __DIR__ . DIRECTORY_SEPARATOR . $path . '.php';
// 3. 加载这个类文件
require $file;
});
需要用的时候,使用文件包含加载一下就可以
namespace ns1;
//调用类自动加载器文件
require __DIR__ . '/autoloader.php';
class Demo2
{
}
// new \php\cn\Demo2;
echo Demo2::class . '<br>';
echo \php\cn\Demo2::class;