__toString方法

再看另外一个魔术方法__TOstring(在这里故意这么写,是要说明PHP中方法不区分大小写,但实际开发中还需要注意规范)。

当进行测试时,需要知道是否得出正确的数据。比如打印一个对象时,看看这个对象都有哪些属性,其值是什么,如果类定义了__toString方法,就能在测试时,echo打印对象体,对象就会自动条用它所属类定义的__toString方法,格式化输出这个对象所包含的数据。如果没有这个方法,那么echo一个对象将报错,例如 “Catchable fatal error: Object of class Sales could not 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/unserialize也是进行序列化的,但是这组函数序列化时会产生一些无用信息,如属性字符串长度,造成存储空间的无谓浪费。因此,可以实现自己的序列化和反序列化方法,或者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_opl;
    zval z_copy;
    zval *z = GET_OPL_ZVAL_PTR(BP_VAR_R);
    //此处的代码预留了把对象转换为字符串的接口
    if (OPL_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_OPL();
        ZEND_VM_NEXT_OPCODE();
}

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

有比较才有认知。最后,针对本节代码给出一个Java版本的代码,供各位同学用来对比两种语言中重载和魔术方法的一桶,代码如下所示:

import org.apache.commons.lang.builder.ToStringBuilder;
/**
 * 类的重载演示Java版本
 * @author lightWay
 * @date
 * @verson
 */
public class Account
{
	private String user; //用户名
	private String pwd; //密码

	public Account()
	{
		System.out.println("构造函数");
	}

	public Account(String user, String pwd)
	{
		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 this.user;
	}

	public void setUser(String user)
	{
		this.user = user;
	}

	public void setPwd(String pwd)
	{

	}

	@Override
	public String toString()
	{
		return ToStringBuilder.reflectionToString(this);
	}

	public static void main(String[] args)
	{
		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或直接修改编译后字节码的方式来实现。这体现了动态语言的优势,简单灵活。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值