PHP对象相关知识总结


Posted in PHP onApril 09, 2017

对象传递:一种说法是“PHP对象是通过引用传递的”,更准确的说法是别名(标识符)传递,即它们都保存着同一个标识符(ID)的拷贝,这个标识符指向同一个对象的真正内容。

<?php
 class A {
   public $foo = 1;
 } 
 
 $a = new A;
 $b = $a;   // $a ,$b都是同一个标识符的拷贝
       // ($a) = ($b) = <id>
 $b->foo = 2;
 echo $a->foo."\n";//2

 $c = new A;
 $d = &$c;  // $c ,$d是引用
       // ($c,$d) = <id>
 
 $d->foo = 2;
 echo $c->foo."\n";//2
 
 $e = new A;
 
 function foo($obj) {
   // ($obj) = ($e) = <id>
   $obj->foo = 2;
 }
 
 foo($e);
 echo $e->foo."\n";//2

•对象复制:对象复制可以通过 clone 关键字来完成,如果原对象定义了 __clone() 方法,则新对象中的 __clone() 方法将在复制完后被调用,__clone() 方法可用于修改复制对象属性的值。当对象被复制后,会对对象的所有属性执行一个浅复制(shallow copy),但所有的引用属性仍然会是一个指向原来的变量的引用。

<?php
 class SubObject
 {
   static $instances = 0;
   public $instance;
 
   public function __construct()
   {
     $this->instance = ++self::$instances;
   }
 
   public function __clone()
   {
     $this->instance = ++self::$instances;
   }
 }
 
 class MyCloneable
 {
   public $object1;
   public $object2;
 
   function __clone()
   {
     // 强制复制一份this->object, 否则仍然指向同一个对象
     $this->object1 = clone $this->object1;
   }
   
   function cloneTest()
   {
     echo 'cloneTest';
   }
 }
 
 $obj = new MyCloneable();
 
 $obj->object1 = new SubObject();
 $obj->object2 = new SubObject();
 
 $obj2 = clone $obj;
 
 print("Original Object:\n");
 print_r($obj);
 
 print("Cloned Object:\n");
 print_r($obj2);
 echo $obj2->cloneTest().":\n";
 echo (new Reflectionclass($obj2));

上例输出结果:

Original Object:
MyCloneable Object
(
  [object1] => SubObject Object
    (
      [instance] => 1
    )

  [object2] => SubObject Object
    (
      [instance] => 2
    )

)
Cloned Object:
MyCloneable Object
(
  [object1] => SubObject Object
    (
      [instance] => 3
    )

  [object2] => SubObject Object
    (
      [instance] => 2
    )

)
cloneTest:
Class [ <user> class MyCloneable ] {
 @@ /public/t.php 18-33

 - Constants [0] {
 }

 - Static properties [0] {
 }

 - Static methods [0] {
 }

 - Properties [2] {
  Property [ <default> public $object1 ]
  Property [ <default> public $object2 ]
 }

 - Methods [2] {
  Method [ <user> public method __clone ] {
   @@ /public/t.php 23 - 27
  }

  Method [ <user> public method cloneTest ] {
   @@ /public/t.php 29 - 32
  }
 }
}

•对象遍历: foreach只能遍历对象的可见属性,无法遍历其方法,实现起来比较容易;另外,也可通过实现Iterator接口或IteratorAggregate接口的方法遍历对象属性。

•类型约束: PHP作为一种弱类型语言,类型约束可以让编程更加规范,也少出些差错;类型约束不只能用在对象定义中,也能用在函数定义中。类型约束可指定对象、接口、array、callable(闭包callback),类型约束用来保证实际数据类型与原型定义一致,不一致则抛出一个可捕获的致命错误;不过如果定义了默认值为NULL,那么实参可以是NULL;类型约束不能用于标量类型如 int 或 string,Traits 也不允许。

•对象序列化与还原:函数serialize()可将打成包含字节流的字符串便于存储对象,函数unserialize()能够还原字符串为对象。但有一个前提是,无论序列化还是反序列化,对象的类定义已经完成,即需要先导入类(文件)。

•重载:PHP的重载包括属性和方法,更像一个套用说法,不支持常见的重载语法规范,具有不可预见性,影响范围更宽泛,就是利用魔术方法(magic methods)来调用当前环境下未定义或不可见的类属性或方法。所有重载方法都必须被声明为 public(这一条应该比较好理解,别人可能因不可见才需要你,那你自己必须可见才行),参数也不能通过引用传递(重载方法具有不可预见性,估计出于安全方面的考虑吧,防止变量被随意引用)。在除 isset() 外的其它语言结构中无法使用重载的属性,这意味着当对一个重载的属性使用 empty() 时,重载魔术方法将不会被调用; 为避开此限制,必须将重载属性赋值到本地变量再使用 empty(),可见重载属性是介于合法属性与非法属性之间的存在。

[属性重载]:这些方法不能被声明为 static,在静态方法中,这些魔术方法将不会被调用
public void __set ( string $name , mixed $value )
在给不可访问属性赋值时,__set() 会被调用

public mixed __get ( string $name )
读取不可访问属性的值时,__get() 会被调用

public bool __isset ( string $name )
当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用

public void __unset ( string $name )
当对不可访问属性调用 unset() 时,__unset() 会被调用

Note:
因为 PHP 处理赋值运算的方式,__set() 的返回值将被忽略。类似的, 在下面这样的链式赋值中,__get() 不会被调用:
 $a = $obj->b = 8;

[方法重载]:
public mixed __call ( string $name , array $arguments )
在对象中调用一个不可访问方法时,__call() 会被调用

public static mixed __callStatic ( string $name , array $arguments )
在静态上下文中调用一个不可访问方法时,__callStatic() 会被调用

•静态属性和方法:static 关键字用来定义静态属性、静态方法,静态属性不能通过实例化的对象-> 来访问(但静态方法可以)。静态属性只能被初始化为常量表达式,所以可以把静态属性初始化为整数或数组,但不能初始化为另一个变量或函数返回值,也不能指向一个对象。可以用一个变量表示类来动态调用静态属性,但该变量的值不能为关键字 self,parent 或 static。

class Foo
 {
   public static $my_static = 'foo';
 
   public function staticValue() {
     return self::$my_static;
   }
 }
 
 class Bar extends Foo
 {
   public function fooStatic() {
     return parent::$my_static;
   }
 }
 
 
 print Foo::$my_static . "\n";
 
 $foo = new Foo();
 print $foo->staticValue() . "\n";
 print $foo->my_static . "\n";   // Undefined "Property" my_static 
 
 print $foo::$my_static . "\n";
 $classname = 'Foo';
 print $classname::$my_static . "\n"; // As of PHP 5.3.0
 
 print Bar::$my_static . "\n";
 $bar = new Bar();
 print $bar->fooStatic() . "\n";

•后期静态绑定:static:: 定义后期静态绑定工作原理是存储了上一个“非转发调用”(non-forwarding call)的类名。当进行静态方法调用时,该类名即为明确指定的那个(通常在 :: 运算符左侧部分);当进行非静态方法调用时,即为该对象所属的类。使用 self:: 或者 __CLASS__ 对当前类的静态引用,取决于定义当前方法所在的类;static:: 不再被解析为定义当前方法所在的类,而是在实际运行时计算的,可以用于静态属性和所有方法的调用。

<?php
 class A
 {
   
   private $proPrivate = "private of A";
   protected $proProtected = "protected of A";
   public $proPublic = "public of A";
   
   private function foo()
   {
     echo $this->proPrivate."\n";
     echo $this->proProtected."\n";
     echo $this->proPublic."\n";
   }
   
   public function test()
   {
     $this->foo();
     static::foo();
   }
 }
 
 class B extends A
 {
  /* foo() will be copied to B, hence its scope will still be A and
   * the call be successful */
 }
 
 class C extends A
 {
   private $proPrivate = "private of C";
   protected $proProtected = "protected of C";
   public $proPublic = "public of C";
   
   private function foo()
   {
     /* original method is replaced; the scope of the new one is C */
     echo "I am C\n";
   }
   
   public function myFoo()
   {
     //parent::foo();
     $this->foo();
   }
 }
 
 echo "Class B:\n";
 $b = new B();
 $b->test();
 echo "\nClass C:\n";
 $c = new C();
 $c->myFoo();
 $c->test();  //fails

上例输出结果:

Class B:
private of A
protected of A
public of A
private of A
protected of A
public of A

Class C:
I am C
private of A
protected of C
public of C 
Fatal error: Uncaught Error: Call to private method C::foo() from context 'A' in /public/t.php:19 Stack trace: #0 /public/t.php(54): A->test() #1 {main} thrown in /public/t.php on line 19

•继承:官方文档对继承有这样一段描述“当扩展一个类,子类就会继承父类所有公有的和受保护的方法。除非子类覆盖了父类的方法,被继承的方法都会保留其原有功能”,言下之意似乎私有属性和方法不会被继承;然而上例又告诉我们子类拥有与父类一致的属性和方法,继承就是全盘复制,这才能满足我们对继承编程的需求,如果私有的不能继承,子类就必须自行重新定义,在大多数时候没有必要。另外就是可见性问题,父类的私有属性和方法在子类是不可见的。上例还告诉我们对象实际执行的域要考虑可见性、继承、后期静态绑定机制。

PHP 相关文章推荐
如何过滤高亮显示非法字符
Oct 09 PHP
PHP中Date获取时间不正确怎么办
Jun 05 PHP
php array_map array_multisort 高效处理多维数组排序
Jun 11 PHP
查找mysql字段中固定字符串并替换的几个方法
Sep 23 PHP
基于php冒泡排序算法的深入理解
Jun 09 PHP
跟我学Laravel之请求(Request)的生命周期
Oct 15 PHP
CodeIgniter使用smtp服务发送html邮件的方法
Jun 10 PHP
php限制文件下载速度的代码
Oct 20 PHP
php中session定期自动清理的方法
Nov 12 PHP
thinkPHP使用post方式查询时分页失效的解决方法
Dec 09 PHP
PHP动态地创建属性和方法, 对象的复制, 对象的比较,加载指定的文件,自动加载类文件,命名空间
May 06 PHP
php 多继承的几种常见实现方法示例
Nov 18 PHP
YII2框架中使用yii.js实现的post请求
Apr 09 #PHP
PHP使用SWOOLE扩展实现定时同步 MySQL 数据
Apr 09 #PHP
CentOS系统中PHP安装扩展的方式汇总
Apr 09 #PHP
PHP将身份证正反面两张照片合成一张图片的代码
Apr 08 #PHP
ThinkPHP中调用PHPExcel的实现代码
Apr 08 #PHP
yii框架无限极分类的实现方法
Apr 08 #PHP
PHP下载远程图片的几种方法总结
Apr 07 #PHP
You might like
PHP生成随机字符串(3种方法)
2015/09/25 PHP
laravel框架如何设置公共头和公共尾
2019/10/22 PHP
PHP+Mysql分布式事务与解决方案深入理解
2021/02/27 PHP
Locate a File Using a File Open Dialog Box
2007/06/18 Javascript
JavaScript 对象模型 执行模型
2009/12/06 Javascript
JS判断文本框内容改变事件的简单实例
2014/03/07 Javascript
JavaScript判断浏览器类型的方法
2015/02/10 Javascript
JS实现的tab切换选项卡效果示例
2017/02/28 Javascript
基于JavaScript实现报警器提示音效果
2017/10/27 Javascript
jQuery实现checkbox即点即改批量删除及中间遇到的坑
2017/11/11 jQuery
微信小程序实现MUI数字输入框效果
2018/01/31 Javascript
vue与原生app的对接交互的方法(混合开发)
2018/11/28 Javascript
详解element-ui日期时间选择器的日期格式化问题
2019/04/08 Javascript
微信小程序学习总结(三)条件、模板、文件引用实例分析
2020/06/04 Javascript
Element Dropdown下拉菜单的使用方法
2020/07/26 Javascript
vue动画—通过钩子函数实现半场动画操作
2020/08/09 Javascript
[47:08]OG vs INfamous 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/17 DOTA
python 基础学习第二弹 类属性和实例属性
2012/08/27 Python
Python中max函数用法实例分析
2015/07/17 Python
Python中Iterator迭代器的使用杂谈
2016/06/20 Python
python利用ffmpeg进行录制屏幕的方法
2019/01/10 Python
新年快乐! python实现绚烂的烟花绽放效果
2019/01/30 Python
Python Django给admin添加Action的方法实例详解
2019/04/29 Python
django框架防止XSS注入的方法分析
2019/06/21 Python
如何使用Python自动控制windows桌面
2019/07/11 Python
Python json转字典字符方法实例解析
2020/04/13 Python
css3实现多个元素依次显示效果
2017/12/12 HTML / CSS
HTML5触摸事件演化tap事件介绍
2016/03/25 HTML / CSS
HTML5声音录制/播放功能的实现代码
2018/05/03 HTML / CSS
个人查摆剖析材料
2014/02/04 职场文书
2014年六一儿童节演讲稿
2014/05/23 职场文书
服装设计专业自荐信
2014/06/17 职场文书
2014个人年度工作总结范文
2014/12/24 职场文书
全国爱牙日活动总结
2015/02/05 职场文书
5.12护士节活动总结
2015/02/10 职场文书
anaconda python3.8安装后降级
2021/06/11 Python