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 相关文章推荐
动态生成gif格式的图像要注意?
Oct 09 PHP
一个PHP操作Access类(PHP+ODBC+Access)
Jan 02 PHP
PHP5 安装方法
Jan 15 PHP
ie6 动态缩略图不显示的原因
Jun 21 PHP
php性能优化分析工具XDebug 大型网站调试工具
May 22 PHP
php创建无限级树型菜单
Nov 05 PHP
joomla数据库操作示例代码
Jan 06 PHP
yii2中使用Active Record模式的方法
Jan 09 PHP
thinkphp中多表查询中防止数据重复的sql语句(必看)
Sep 22 PHP
PHP面向对象程序设计(OOP)之方法重写(override)操作示例
Dec 21 PHP
Yii框架的布局文件实例分析
Sep 04 PHP
thinkphp框架类库扩展操作示例
Nov 26 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处理文件的小例子(解压缩,删除目录)
2013/02/03 PHP
YII框架页面缓存操作示例
2019/04/29 PHP
php定期拉取数据对比方法实例
2019/09/22 PHP
Javascript 学习书 推荐
2009/06/13 Javascript
JS解析XML的实现代码
2009/11/12 Javascript
JSON JQUERY模板实现说明
2010/07/03 Javascript
jQuery随机切换图片的小例子
2013/04/18 Javascript
提高jQuery性能的十个诀窍
2013/11/14 Javascript
js数组转json并在后台对其解析具体实现
2013/11/20 Javascript
jQuery实现动画效果的简单实例
2014/01/27 Javascript
Jquery中基本选择器用法实例详解
2015/05/18 Javascript
解决JavaScript数字精度丢失问题的方法
2015/12/03 Javascript
微信小程序动态生成二维码的实现代码
2018/07/25 Javascript
NodeJS 实现多语言的示例代码
2018/09/11 NodeJs
angular6的响应式表单的实现
2018/10/10 Javascript
arctext.js实现文字平滑弯曲弧形效果的插件
2019/05/13 Javascript
js getBoundingClientRect使用方法详解
2019/07/17 Javascript
javascript实现blob加密视频源地址的方法
2019/08/08 Javascript
用Python中的字典来处理索引统计的方法
2015/05/05 Python
Python实现一个转存纯真IP数据库的脚本分享
2017/05/21 Python
利用anaconda作为python的依赖库管理方法
2019/08/13 Python
python 链接sqlserver 写接口实例
2020/03/11 Python
python对XML文件的操作实现代码
2020/03/27 Python
Python图像识别+KNN求解数独的实现
2020/11/13 Python
Get The Label中文官网:英国运动时尚购物平台
2017/04/19 全球购物
Kate Spade美国官网:纽约新兴时尚品牌,以包包闻名于世
2017/11/09 全球购物
世界领先的电子书网站:eBooks.com(在线购买小说、非小说和教科书)
2019/03/30 全球购物
新西兰最大、占有率最高的综合性药房:PharmacyDirect药房中文网
2020/11/03 全球购物
MySQL面试题目集锦
2016/04/14 面试题
函授毕业自我鉴定
2013/12/19 职场文书
王力宏牛津大学演讲稿
2014/05/22 职场文书
2014年最新离婚协议书范本
2014/10/11 职场文书
历史博物馆观后感
2015/06/05 职场文书
签字仪式主持词
2015/07/03 职场文书
《少年闰土》教学反思
2016/02/18 职场文书
Win11怎么解除儿童账号限制?Win11解除微软儿童账号限制方法
2022/07/07 数码科技