最新消息:

PHP _toString方法

编程 2090浏览

当进行测试时,需要知道是否得出正确的数据。比如打印一个对象时,看看这个对象都有哪些属性,其值是什么,如果类定义了 _toString方法,就能在测试时,echo 打印对象体,对象就会自动调用它所属类定义的 _toString方法,格式化输出这个对象所包含的数据。如果没有这个方法,那么 echo 一个对象将报错,例如: “Catchable fatal error: Object of class Account couldnot be converted to string” 语法错误,实际上这是一个类型匹配失败错误。不过仍然可以用 print_r() 和 var_dump() 函数输出一个对象。当然,_toString 是可以定制的,所提供的信息和样式更丰富。

<? php
class Account {
 public $user=1;
 private $pwd=2; // 自定义的格式化输出方法
 public function toString() {
 return "当前对象的用户名是{$this->user},密码是{$this->pwd}";
 }
}
$a=new Account();
echo $a;
echo PHP_EOL;
print_r($a);

运行这段代码发现,使用 _toString方法后,输出的结果是可定制的,更易于理解。实际上,PHP 的 _toString 魔术方法的设计原型来源于 Java。Java 中也有这么一个方法,而且在 Java 中,这个方法被大量使用,对于调试程序比较方便。实际上,_toString方法也是一种序列化,我们知道 PHP 自带 serialize/un-serialize 也是进行序列化的,但是这组函数序列化时会产生一些无用信息,如属性字符串长度,造成存储空间的无谓浪费。因此,可以实现自己的序列化和反序列化方法,或者 json_encode/json_decode 也是一个不错的选择。

为什么直接 echo 一个对象就会报语法错误,而如果这个对象实现 _toString方法后就可以直接输出呢?原因很简单,echo 本来可以打印一个对象,而且也实现了这个接口,但是 PHP 对其做了个限制,只有实现 _toString 后才允许使用。从下面的 PHP 源代码里可以得到验证:

ZEND_VM_HANDLER(40, ZEND_ECHO, CONST|TMP|VAR|CV, ANY) {
 zend_op *opline = EX(opline);
 zend_free_op free_op1;
 zval z_copy;
 zval *z = GET_OP1_ZVAL_PTR(BP_VAR_R); // 此处的代码预留了把对象转换为字符串的接口
 if (OP1_TYPE != IS_CONST && Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL && zend_std_cast_object_tostring(z, &z_copy, IS_STRING TSRMLS_CC) == SUCCESS) {
 zend_print_variable(&z_copy);
 zval_dtor(&z_copy);
 }
 else {
 zend_print_variable(z);
 }
 FREE_OP1();
 ZEND_VM_NEXT_OPCODE();
}

由此可见,魔术方法并不神奇。

有比较才有认知。最后,针对本文代码给出一个 Java 版本的代码,供各位小伙伴们用来对比两种语言中重载和魔术方法的异同。

import org.apache.commons.lang3.builder.ToStringBuilder;
public class Account {
 private String user;// 用户名
 private String pwd; // 密码
 public Account() {
 System.out.println("构造函数");
 }
 public Account(String user,String pwd) {
 System.out.println("重载构造函数");
 System.out.println(user+"---"+pwd);
 }
 public void say(String user) {
 System.out.println("用户是:"+user);
 }
 public void say(String user,String pwd) {
 System.out.println("用户:"+user);
 System.out.println("密码"+pwd);
 }
 public String getUser() {
 return user;
 }
 public void setUser(String user) {
 this.user = user;
 }
 public String getPwd() {
 return pwd;
 }
 public void setPwd(String pwd) { }
 @Override public String toString() {
 return ToStringBuilder.reflectionToString(this);
 }
 public static void main(String…) {
 Account account=new Account();
 account.setUser("张三");
 account.setPwd("123456");
 account.say("李四");
 account.say("王五","123");
 System.out.println(account);
 }
}

可以看出,Java 的构造方法比 PHP 好用,PHP 由于有了 _set/_get 这一对魔术方法,使得动态增加对象的属性字段变得很方便,而对 Java 来说,要实现类似的效果,就不得不借助反射 API 或直接修改编译后字节码的方式来实现。这体现了动态语言的优势,简单、灵活。

好了,PHP _toString方法 就分享到这里,非常感谢你的来访。如果你很喜欢本站,请不要忘记收藏本站,以便下次继续访问;也可以 关注站长微博 随时获取最新动态。你的支持就是我最大的动力!

转载请注明:爱维科斯 » PHP _toString方法

支付宝打赏支付宝打赏 微信打赏微信打赏

如果文章对你有帮助,欢迎点击上方按钮打赏作者