如何创建一个可以转换为布尔值的php类(be truthy或falsy)

SWi*_*ilk 9 php boolean class

我正在创建一个集合类,并希望它是我目前使用的数组的替代品.

如何创建一个可以转换为布尔值的类,所以这个类可以是真的还是伪造的?

一个简单的测试表明空类的对象是真实的:

class boolClass {}
$obj = new boolClass();
var_dump( (bool)$obj);
//prints 
//bool(true)
Run Code Online (Sandbox Code Playgroud)

但是我需要决定我的班级是真的还是假的.有没有办法告诉PHP引擎如何将我的类转换为布尔值?就像我可以用__toString()做的那样?

背景:

让我们说我写了一个这样的类(这只是一个例子):

class MyCollection implements ArrayAccess, Iterator {
    //...
}
Run Code Online (Sandbox Code Playgroud)

我目前大量使用这种模式:

$var = array();

if (empty($var)) {
   //array is empty, (or there is no array at all)
   // I do something here
}
Run Code Online (Sandbox Code Playgroud)

我希望看起来像:

$var = new MyCollection(array());
Run Code Online (Sandbox Code Playgroud)

并保持其余不变.但是包含MyCollection的$ var总是很简单所以我需要满足以下所有条件:

if ($var->isEmpty()) {
    //...
}
Run Code Online (Sandbox Code Playgroud)

但这是不可接受的,因为我的代码库有很多兆字节.

有解决方案吗?

小智 22

经过多次焦虑,失望和黑客攻击后 - 我相信我找到了解决方案.该解决方案不要求任何扩展; 它可以用很少量的PHP样板实现.但是,在自己实施此解决方案之前,请注意这是 - 实际上 - 这是一个巨大的黑客攻击.话虽这么说,这是我发现的:

很沮丧,我花了一些时间查看BooleansPHP文档.虽然用户创建的类被简单地拒绝了作为布尔值转换的能力,但是一个类 - 奇怪的是 - 提供了这种能力.精明的读者会注意到这个类正是内置的SimpleXmlElement.通过演绎过程,假设SimpleXmlElement的任何子类也将继承其独特的布尔铸造功能似乎是公平的.虽然从理论上讲这种方法似乎是有效的,但围绕SimpleXmlElement的神奇之处还在于消除了这种方法的实用性.要理解这是为什么,请考虑以下示例:

class Truthy extends SimpleXmlElement { }
Run Code Online (Sandbox Code Playgroud)

Truthy是SimpleXmlElement的子类,所以我们应该能够测试它是否继承了它的特殊boolean-casting属性:

$true = new Truthy('<true>1</true>'); // XML with content eval's to TRUE
if ($true) echo 'boolean casting is happening!'; 
$false = new Truthy('<false></false>'); // empty XML eval's to FALSE
if (!$false) echo 'this is totally useful!';
Run Code Online (Sandbox Code Playgroud)

实际上,Truthy继承了SimpleXmlElement提供的boolean-casting属性.但是,这种语法很笨拙,并且不太可能从这个类中获得很多实用程序(至少与本机使用SimpleXmlElement相比).这种情况是问题开始出现的地方:

$false = new Truthy('<false></false>'); // empty XML eval's to FALSE
$false->reason = 'because I said so'; // some extra info to explain why it's false
if (!$false) echo 'why is this not false anymore?!?';
else echo 'because SimpleXMLElements are magical!';
Run Code Online (Sandbox Code Playgroud)

如您所见,尝试在子类上设置属性会立即破坏我们从继承的boolean-casting获得的实用程序.不幸的是,SimpleXmlElement有另一个神奇的功能,打破了我们的惯例.显然,当您设置SimpleXmlElement的属性时,它会修改XML!你自己看:

$xml = new SimpleXmlElement('<element></element>');
xml->test = 'content';
echo $xml->asXML(); // <element><test>content</test></element>
Run Code Online (Sandbox Code Playgroud)

那么我们可以从子类化SimpleXmlElement获得任何实用程序!值得庆幸的是,经过多次黑客攻击,我找到了一种方法来将信息保存到这个子类中,而不会破坏布尔铸造魔法:评论!

$false = new Truthy('<!-- hello world! --><false></false>');
if (!$false) echo 'Great Scott! It worked!';
Run Code Online (Sandbox Code Playgroud)

进展!我们能够在不破坏boolean-casting的情况下将有用的信息输入到这个类中!好的,现在我们需要做的就是清理它,这是我的最终实现:

class Truthy extends SimpleXMLElement {

public function data() {

    preg_match("#<!\-\-(.+?)\-\->#", $this->asXML(), $matches);

    if (!$matches) return null;

    return unserialize(html_entity_decode($matches[1]));


}

public static function create($boolean, Serializable $data = null) {
    $xml  = '<!--' . htmlentities(serialize($data)) . "-->";
    $xml .= $boolean ? '<truthy>1</truthy>' : '<truthy/>';
    return new Truthy($xml);
}

}
Run Code Online (Sandbox Code Playgroud)

为了消除一些笨拙,我添加了一个公共静态工厂方法.现在我们可以创建Truthy对象而不必担心实现细节.工厂允许调用者定义任意数据集,以及布尔流.然后可以在以后调用数据方法以检索此数据的只读副本:

$false = Truthy::create(false, array('reason' => 'because I said so!'));
if (!$false) {
   $data = $false->data();
   echo 'The reason this was false was ' . $data['reason'];
}
Run Code Online (Sandbox Code Playgroud)

你有它!在用户定义的类中进行布尔流换的完全hacky(但可用)方法.如果你在生产代码中使用它,请不要起诉我,它会爆炸.


Ham*_*ite 8

在此页面上,枚举了可以为类定义的魔术方法.

http://www.php.net/manual/en/language.oop5.magic.php#language.oop5.magic.tostring

你证明你已经知道了__toString().

不幸的是,那里没有列出你所要求的神奇方法.所以,我认为现在你唯一的选择是定义一个方法并明确地调用该方法.


Sma*_*sty 6

您可以查看 PHP运算符扩展,您可以使用它来重载许多运算符,包括 == 和 ===。通过此扩展,理论上您应该能够编写与布尔值相当的类,如下所示:

if($object == true)
Run Code Online (Sandbox Code Playgroud)