博客列表 >类与对象之重载和命名空间的概念

类与对象之重载和命名空间的概念

残破的蛋蛋
残破的蛋蛋原创
2021年02月23日 17:51:16783浏览

类与对象之重载和命名空间的概念

一、重载

PHP提供的“重载”是指动态的“创建”类属性和方法。是通过魔术方法来实现的。

当调用当前环境下未定义或不可见的类属性或方法时,重载方法会被调用。

所有的重载方法都必须被声明为 public。

1.1 属性重载

  1. public __set ( string $name , mixed $value ) : void
  2. public __get ( string $name ) : mixed
  3. public __isset ( string $name ) : bool
  4. public __unset ( string $name ) : void

在给不可访问属性赋值时,__set() 会被调用。

读取不可访问属性的值时,__get() 会被调用。

当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用。

当对不可访问属性调用 unset() 时,__unset() 会被调用。

参数$name是指要操作的变量名称。__set()方法的$value参数指定了$name变量的值。

属性重载只能在对象中进行。在静态方法中这些魔术方法是无效的。因此,这些魔术方法都不能声明为static

  • 示例:使用__get()__set()__isset()__unset()进行属性重载
  1. class Demo
  2. {
  3. // 被重载的数据保存在该数组中
  4. protected $data = [];
  5. // 公有属性
  6. public $age = 31;
  7. // 在给不可访问属性赋值时,__set() 会被调用。
  8. public function __set($name, $value)
  9. {
  10. echo "Set Property ` $name ` valued ` $value `";
  11. return $this->data[$name] = $value;
  12. }
  13. // 读取不可访问属性的值时,__get() 会被调用。
  14. public function __get($name)
  15. {
  16. if (array_key_exists($name, $this->data)) {
  17. return $this->data[$name];
  18. }
  19. }
  20. // 当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用。
  21. public function __isset($name)
  22. {
  23. if (!isset($this->data[$name])) {
  24. echo "$name has not been set. <br>";
  25. } else {
  26. echo "$name has been set. <br>";
  27. }
  28. return isset($this->data[$name]);
  29. }
  30. // 当对不可访问属性调用 unset() 时,__unset() 会被调用。
  31. public function __unset($name)
  32. {
  33. echo "$name has been unset.";
  34. unset($this->data[$name]);
  35. }
  36. }
  37. // 实例化Demo类
  38. $obj = new Demo;
  39. // 给不可访问属性赋值
  40. $obj->username = '残破的蛋蛋';
  41. echo '<br>';
  42. // 访问一个属性
  43. echo $obj->username; // 残破的蛋蛋
  44. echo '<br>';
  45. // 对不可访问属性调用isset()
  46. var_dump(isset($obj->username)); // username has been set. bool(true)
  47. echo '<br>';
  48. // 当对不可访问属性调用 unset()
  49. unset($obj->username); // username has been unset.
  50. echo '<br>';
  51. // 再次对不可访问属性使用isset()检测是否还存在该属性
  52. var_dump(isset($obj->username)); // username has not been set. bool(false)
  53. // 重载不能用于已经定义的属性上
  54. echo $obj->age; // 31

注意:重载不能用在已经被定义的属性上。

1.2 方法重载

在对象中调用一个不可访问方法时,__call()会被调用。

在静态上下文中调用一个不可访问方法时,__callStatic()会被调用。

$name参数是要调用的方法名称。$arguments参数是一个枚举数组,包含着要传递给方法$name的参数。

  • 语法示例
  1. public __call ( string $name , array $arguments ) : mixed
  2. public static __callStatic ( string $name , array $arguments ) : mixed

其中__callStatic的版本要求在PHP 5.3.0+

  • 示例:使用__call()__callStatic()对方法重载
  1. class Demo
  2. {
  3. // 方法重载
  4. // 在对象中调用一个不可访问方法时,` __call() `会被调用。
  5. public function __call($name, $arguments)
  6. {
  7. $len = count($arguments);
  8. echo "Calling object method $name contains $len arguments.";
  9. }
  10. // 在静态上下文中调用一个不可访问方法时,` __callStatic() `会被调用。
  11. public static function __callStatic($name, $arguments)
  12. {
  13. $len = count($arguments);
  14. echo "Calling static method $name contains $len arguments.";
  15. }
  16. }
  17. // 实例化Demo类
  18. $obj = new Demo;
  19. // 方法重载
  20. $obj->getName('残破的蛋蛋', '男', 18); // Calling object method getName contains 3 arguments.
  21. echo '<br>';
  22. Demo::getUserInfo('拤碎的蛋蛋', '女', 31); // Calling static method getUserInfo contains 3 arguments.

二、命名空间

2.1 命名空间的概念

什么是命名空间?从广义上来说,命名空间是一种封装事物的方法。在很多地方都可以见到这种抽象概念。例如,在操作系统中目录用来将相关文件分组,对于目录中的文件来说,它就扮演了命名空间的角色。

在 PHP 中,命名空间用来解决在编写类库或应用程序时创建可重用的代码如类或函数时碰到的两类问题:

  1. 用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。
  2. 为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。

PHP 命名空间 提供了一种将相关的类、函数和常量组合到一起的途径。

2.2 命名空间的定义

2.2.1 命名空间的声明

命名空间通过关键字namespace来声明。并且必须在PHP文件的最前面声明命名空间(declare除外)。

  • 语法示例:
  1. namespace ns;
  2. // 类
  3. class Model
  4. {
  5. // TODO
  6. }
  7. // 常量
  8. const PATH = '/models/';
  9. // 函数
  10. function set()
  11. {
  12. // TODO
  13. }

如果按照下面的方法声明命名空间,将会报致命错误。

  1. <html>
  2. <?php
  3. namespace ns; // 致命错误 - 命名空间必须是程序脚本的第一条语句。
  4. ?>
  • 上述代码将会报错:

命名空间的致命错误

2.2.2 命名空间的成员的访问

PHP命名空间成员的访问类似于根据文件的路径访问某个文件,比如:在电脑的E盘下的www文件夹有一个index.php文件,那么我们访问这个文件的路径就是E:/www/index.php

  1. namespace ns1 {
  2. // 类
  3. class Model
  4. {
  5. //....
  6. }
  7. // 常量
  8. const PATH = '/models/';
  9. // 函数
  10. function set()
  11. {
  12. //...
  13. }
  14. echo Model::class . "<br>"; // ns1\Model
  15. echo PATH::class . "<br>"; // ns1\PATH
  16. echo set::class . "<hr>"; // ns1\set
  17. }

通常,我们为了防止一个空间中的代码过大,可以将同一个空间的代码写到多个脚本中去。

例如:有一个PHP文件下有一个名为ns的命名空间,由于该文件过大,现在将其拆分成两个单独的脚本文件,demo1.phpdemo2.php

  • demo1.php文件
  1. namespace ns {
  2. class Demo1
  3. {
  4. // 假设这里有500行代码
  5. public function __construct()
  6. {
  7. echo 1;
  8. }
  9. }
  10. }
  • demo2.php文件
  1. namespace ns {
  2. class Demo2
  3. {
  4. // 假设这里有800行代码
  5. public function __construct()
  6. {
  7. }
  8. }
  9. }
  • 现在我们在demo.php脚本中引用这两个文件
  1. namespace ns;
  2. require 'demo1.php';
  3. require 'demo2.php';
  4. echo Demo1::class, '<br>'; // ns\Demo1
  5. echo Demo2::class, '<br>'; // ns\Demo2

2.2.3 子命名空间

与目录和文件的关系很象,PHP 命名空间也允许指定层次化的命名空间的名称。因此,命名空间的名字可以使用分层次的方式定义:

  1. // 父空间
  2. namespace ns1
  3. {
  4. class Demo
  5. {
  6. # TODO
  7. }
  8. echo Demo::class,'<br>'; // ns1\Demo
  9. // 访问它的子空间成员
  10. // namespace:用在空间中,表示当前空间的引用,类似于$this,self
  11. // echo namespace\ns2\Demo::class,'<br>'; // ns1\ns2\Demo
  12. echo ns2\Demo::class,'<br>'; // ns1\ns2\Demo
  13. echo ns2\ns3\Demo::class, '<hr>'; // ns1\ns2\ns3\Demo
  14. }
  15. // ns1的子空间
  16. namespace ns1\ns2
  17. {
  18. class Demo
  19. {
  20. # TODO
  21. }
  22. // echo __NAMESPACE__;
  23. echo Demo::class,'<br>'; // ns1\ns2\Demo
  24. echo ns1\ns2\ns3\Demo::class,'<hr>';
  25. }
  26. // ns2的子空间
  27. namespace ns1\ns2\ns3
  28. {
  29. class Demo
  30. {
  31. # TODO
  32. }
  33. echo Demo::class,'<br>'; // ns1\ns2\ns3\Demo
  34. // 在ns3中访问上级空间应该怎么办?
  35. echo \ns1\ns2\Demo::class, '<br>'; // ns1\ns2\Demo
  36. echo \ns1\Demo::class, '<br>'; // ns1\Demo
  37. // 全局成员:前面加上全局空间的标识符:\
  38. echo \Demo::class; // Demo
  39. }
  40. namespace
  41. {
  42. class Demo
  43. {
  44. # TODO
  45. }
  46. }
声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议