Php __toString魔法和类型强制

Php __toString魔法和类型强制,php,type-conversion,tostring,magic-methods,Php,Type Conversion,Tostring,Magic Methods,我创建了一个模板类,用于管理视图及其关联数据。它实现了迭代器和数组访问,并允许“子模板”便于使用,如: <p><?php echo $template['foo']; ?></p> <?php foreach($template->post as $post): ?> <p><?php echo $post['bar']; ?></p> <?php endforeach; ?> 通过$

我创建了一个
模板
类,用于管理视图及其关联数据。它实现了
迭代器
数组访问
,并允许“子模板”便于使用,如:

<p><?php echo $template['foo']; ?></p>
<?php foreach($template->post as $post): ?>
    <p><?php echo $post['bar']; ?></p>
<?php endforeach; ?>
通过
$template['foo']='bar'设置值时
在控制器中,
'bar'
的值存储在它自己的
TemplateData
对象中

我使用了神奇的
\uuu toString()
,因此当您回显
模板数据
对象时,它将强制转换为
(字符串)
,并转储其值。然而,尽管mantra控制器和视图不应修改数据,但每当我执行以下操作时:

$template['foo'] = 1;
echo $template['foo'] + 1; //exception
它死在TemplateData类的
对象上,无法转换为int
;除非我将
$template['foo']
重铸为字符串:

echo ((string) $template['foo']) + 1; //outputs 2

有点挫败了要跳出这个圈套的目的对于这种行为是否存在任何解决方法,或者我是否应该认为这是一种偶然防止视图中数据修改的方法?

Echo正在尝试回显
$template['foo']+1
的结果。由于
$template['foo']
是类型为
TemplateData
的对象,
1
int
,因此您收到了一个错误。在这种情况下,
((string)$template['foo'])
不是“重铸”,它是第一次铸造。

PHP不支持。如果您希望能够执行加法(或与运算符相关的任何其他操作),则需要为要支持的每个运算符提供一个方法。很可能在基本模板类上实现它就足以满足常见情况,允许以后在必要时对其进行扩展。虽然在对象上使用
(string)
是一种快捷方式,但我建议不要这样做。

我稍微改变了我的实现,目前似乎还可以;我已经将
\uu invoke()
方法添加到
TemplateData
类中,该类返回
$\u data
属性,不需要进行类型转换而保持不变。因此,在实践中:

//in controller
$template['foo'] = 'bar';
$template['abc'] = 123;

//in view
echo $template['foo']();                       //bar
echo $template['foo']->asHash('md5');          //37b51d194a7513...
echo $template['abc']();                       //123
echo $template['abc']() + 123;                 //246
echo $template['abc']->asHash('md5');          //202cb962ac5907...

//__invoke also takes $function and $arguments for alternative syntax
echo $template['foo']('asHash', array('md5')); //37b51d194a7513...
我想,既然我征服了这座山,我的下一步将是以某种方式允许锁链:

echo $template['foo']->asHash('md5')->asCase('upper');
然而,这似乎很难做到。跟踪“连锁状态”是我以前尝试过的事情,但没有成功。从某种意义上讲,使用
\uu invoke()
会很容易(但很麻烦):

echo $template['foo'](
    array('asHash', 'asCase'),          //ordered array of method names
    array(array('md5'), array('upper')) //ordered array of method argument arrays
);

任何人都能看到这些问题,或者其他替代方法的理由吗?

谢谢Taiko;在此范围内进行强制转换,重新转换为
\u toString()
已强制转换
返回(字符串)$this->\u数据另外,在echo上强制转换为
(int)
仍然会抛出错误,因为我正在尝试将对象强制转换为整数。我必须使用字符串,让PHP在看到算术后强制类型。有没有关于如何完全避免这些问题的想法?不幸的是,PHP还没有(或将要)实现
\uuuu-toInt()
\uu-cast()
…啊,我理解你为什么要使用
(string)
来转换字符串,然后添加。但是,使用echo,您还没有在尝试进行加法时调用
\uuuu-toString()
,因为
echo
将尝试仅输出表达式的结果作为一个整体。您可以将
\uu-toInt()
方法添加到
TemplateData
中,然后使用:
echo$template['foo']->\uu-toInt()+1
或者我想添加一个
asInt()
方法,以与您以前的命名约定保持一致。不幸的是,在这种情况下,\u toString()不适用于您。您可以向
模板
类添加另一个方法。您可以覆盖getOffset方法以强制转换为整数,但我怀疑您不希望在所有情况下都使用此方法;是的,正如我提到的,我已经看到了支持操作符重载的扩展,以及补充的魔术方法(
\uu cast($type)
),但当然这些是扩展,我不能在生产中依赖它们。我想完全避免的
(字符串)
快捷方式。我现在在想,除了
TemplateData
对象之外,如果
Template
类使用Taiko的建议来维护类型(在
TemplateData
对象创建时确定),我还可以在
Template
offsetGet()方法中实现一些类型转换特性。。。嗯…大声思考是受欢迎的。我不想接受我自己的答案。我肯定外面有人在思考,不管我陷在什么盒子里。
echo $template['foo'](
    array('asHash', 'asCase'),          //ordered array of method names
    array(array('md5'), array('upper')) //ordered array of method argument arrays
);