После долгих волнений, разочарований и взломов - я думаю, что нашел решение.Решение не требует каких-либо расширений;это может быть реализовано с очень небольшим количеством шаблонов PHP.Однако, прежде чем приступить к реализации этого решения самостоятельно, обратите внимание, что это - ОГРОМНЫЙ взлом.При этом, вот что я обнаружил:
Разочарованный, я потратил некоторое время на просмотр документации PHP для Booleans .В то время как созданные пользователем классы просто лишены возможности быть приведенными как булевы, одному классу - как ни странно - была предоставлена возможность.Проницательный читатель заметит, что этот класс - не что иное, как встроенный SimpleXmlElement .В процессе дедукции кажется справедливым предположить, что любой подкласс SimpleXmlElement также унаследует свою уникальную возможность логического приведения.Хотя теоретически этот подход кажется верным, магия, окружающая SimpleXmlElement, также лишает его полезности.Чтобы понять, почему это так, рассмотрим следующий пример:
class Truthy extends SimpleXmlElement { }
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!';
Действительно, свойство приведения к логическому значению, предоставленное SimpleXmlElement, наследуется Truthy.Тем не менее, этот синтаксис неуклюж, и маловероятно, что кто-то получит большую пользу от этого класса (по крайней мере, если сравнивать с использованием 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!';
Как вы можете видеть, попытка установить свойство в нашем подклассе немедленно ломает утилиту, которую мы получаем из унаследованного логического преобразования.К сожалению для нас, SimpleXmlElement имеет еще одну волшебную особенность, которая нарушает наше соглашение.По-видимому, когда вы устанавливаете свойство SimpleXmlElement, оно изменяет XML!Убедитесь сами:
$xml = new SimpleXmlElement('<element></element>');
xml->test = 'content';
echo $xml->asXML(); // <element><test>content</test></element>
Ну, есть любая утилита, которую мы получили бы от создания подкласса SimpleXmlElement!К счастью, после долгих взломов я нашел способ сохранить информацию в этом подклассе, не нарушая магию булевского кастинга: комментарии!
$false = new Truthy('<!-- hello world! --><false></false>');
if (!$false) echo 'Great Scott! It worked!';
Прогресс!Мы смогли получить полезную информацию в этом классе, не нарушая логическое приведение!Хорошо, теперь все, что нам нужно сделать, это очистить его, вот моя окончательная реализация:
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);
}
}
Чтобы удалить некоторую неуклюжесть, я добавил публичный статический метод фабрики.Теперь мы можем создать объект 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'];
}
Вот и все!Совершенно хакерский (но пригодный для использования) способ выполнить логическое приведение в пользовательских классах.Пожалуйста, не судитесь со мной, если вы используете это в рабочем коде, и он взорвется.