3v4l.org

run code in 200+ php & hhvm versions
Bugs & Features
<?php // // The goal is to try to safely cast an object to string but only if it can reasonably // be assumed to be stringable. (properly implements __toString) // // This is as close as I've been able to come to ensure that bad things do not get // called and I only deal with proper string results. // // The only major edge case here is that without implementing reflection it is // impossible to know if __toString was implemented as a static method. This // is a bummer but I'm willing to call this one "good enough." // class HasValidToString { public function __toString() { return 'Object\'s __toString is valid'; } } class HasNonPublicToString { protected function __toString() { return 'has non public __toString'; } } class HasNullToStringReturnValue { public static function __toString() { } } class HasNumberReturnValue { public function __toString() { return 5; } } class HasObjectReturnValue { public function __toString() { return new HasValidToString(); } } // Do to PHP's fuzzy nature on how to handle things like this, you'll get a warning that // this method should not be static but it will happily let you call it on an object // instance so even though you might say that this is expected to fail it actually // won't. Chances are something else awful will happen, though. Short of dipping // into Reflection I'm not sure how to guard against this such that we do not // call into a static __toString method. class HasStaticToString { public static function __toString() { return 'Object\'s __toString is static; should not be able to call it'; } } $isExpectedToPass = true; $isExpectedToFail = false; function safely_cast_object_to_string($object) { if (! method_exists($object, '__toString')) { throw new InvalidArgumentException('Object has no __toString'); } if (! is_callable([$object, '__toString'])) { throw new InvalidArgumentException('Object\'s __toString is not callable'); } $string = $object->__toString(); if (! is_string($string)) { throw new InvalidArgumentException('Object\'s __toString does not return a string value'); } return $string; } foreach ([ [new HasValidToString(), $isExpectedToPass], [new HasNonPublicToString(), $isExpectedToFail], [new HasNullToStringReturnValue(), $isExpectedToFail], [new HasNumberReturnValue(), $isExpectedToFail], [new HasObjectReturnValue(), $isExpectedToFail], [new HasStaticToString(), $isExpectedToFail], // it actually passes... ] as $test) { list ($sample, $expectation) = $test; $actual = false; $string = null; $message = ''; try { $string = safely_cast_object_to_string($sample); $actual = true; } catch (\InvalidArgumentException $e) { $message = $e->getMessage(); } printf( "%26s [%s] %s\n", get_class($sample), $actual === $expectation ? 'PASS' : 'FAIL', ! is_null($string) ? $string : $message ); }
based on bbdgF
Output for 5.5.0 - 7.2.6
Warning: The magic method __toString() must have public visibility and cannot be static in /in/nsetu on line 16 Warning: The magic method __toString() must have public visibility and cannot be static in /in/nsetu on line 17 Warning: The magic method __toString() must have public visibility and cannot be static in /in/nsetu on line 28 HasValidToString [PASS] Object's __toString is valid HasNonPublicToString [PASS] Object's __toString is not callable HasNullToStringReturnValue [PASS] Object's __toString does not return a string value HasNumberReturnValue [PASS] Object's __toString does not return a string value HasObjectReturnValue [PASS] Object's __toString does not return a string value HasStaticToString [FAIL] Object's __toString is static; should not be able to call it