On Sun, Feb 26, 2012 at 10:57 PM, Anthony Ferrara <ircmax...@gmail.com> wrote: > I've gone back and re-read a bunch of the old posts on Type Hinting, > and have come to the conclusion that it won't be done any time soon. > Not because it doesn't have merit, but because there are at least a > few fundamental difficulties that are non-trivial to figure out while > still keeping the usefulness. > > So, I started thinking of a way that we can work around it. One > technique that has been passed around is to use object wrappers and > pass objects instead of scalars. Such as was suggested in: > http://marc.info/?l=php-internals&m=119543188808737&w=2 > > One of the problems associated with this, is that before you work with > these types, you need to manually cast them back to the native type > they represent. We can try to deal with this problem using > __toString, but I don't think that's granular enough to really be of > much use in solving this problem... > > Another method we could use, is if we supported operator overloading > in objects. That way, we could overload the addition operator to > handle the operation. However, this becomes quite problematic, since > ordering of operations and interaction with disparate class trees is > going to get rather messy (and extremely fragile) quite quick. > > Let me throw out another possible solution. What if we added two new > magic methods to objects: > > public function __castTo($type); > public static function __castFrom($value); > > With these two methods, we could enable type-hinting by using > something very similar to auto-boxing. Let me start with a sample > implementation: > > class Integer { > protected $value = 0; > public function __construct($value) { > $this->value = $value; > } > public function __castTo($type) { > switch ($type) { > case 'int': > case 'numeric': > return $this->value; > case 'float': > return (float) $this->value; > } > throw new LogicException('Illegal Cast Operation Performed'); > } > public static function __castFrom($value) { > if (!is_scalar($value)) { > throw new LogicException('Illegal Cast Operation Performed'); > } > return new static((int) $value); > } > } > > Now, that enables us to do something like: > > $int = new Integer(2); > echo $int + 2; // 4, since __castTo was called with "numeric" > echo substr("foobar", 0, $int); // "fo" since __castTo was called with "int" >
I have to say, it doesn't get work, thinking this: $mixed1 = new Interger(2); $mixed2 = new Interge(3); $guess_what_type_is = $mixed1 + $mixed2; thanks > That demonstrates the __castTo usages. Now for the __castFrom... > > function foo(Integer $int) { > echo $int + 1; > } > > Now, under current rules, calling foo(1) would result in a fatal > error. However, we could change that to check if the class being > type-hinted for has a __castFrom method on it. If it does, it would > attempt to cast the value into that class. So calling foo(1) would > actually internally call `Integer::__castFrom(1)`. And since that > returns an object of instance Integer, the hint would pass. > > These two additions would solve a few issues with type-hinting. First > off, it solves the "cast to" vs "error if" debate on passing a string > in the place of an integer. In this case, it would be up to the > __castFrom() method to determine that (thereby enabling both worlds > possible). Second, it solves the problem of having to wrap clumsy > APIs around scalars for hinting purposes ($foo->getInteger() + 1). > Third, it is still completely optional... Fourth, it keeps and tries > to embrace the dynamic type-cohersion nature of PHP... > > Now, that's not to say it's not without problems. Here are a few that > I can think of: > > 1. How should it deal with references? If I do `function foo(Integer > &$int)`, what should happen? > - I would argue that if you're trying to reference, the casting > functionality should not be expected to work at all. But that > introduces some inconsistency there. Not sure how to solve that... > > 2. Should it support casting from one object to another? Meaning if I > pass an SPLInt to something expecting Integer (from two different > trees), should __castFrom be called? > - I would argue that yes, it should. That would open the door for > compatibility layers to be built for cross-framework interaction that > happens seamlessly regardless of what was passed in. But it could get > a bit interesting, since that also could wind up having really > non-obvious side-effects, mainly because of object references... > > 3. Should "class casting" then be supported? We can currently do > (int) $foo. Should we then be able to specify a class in the cast > instead? (Integer) $foo? > - I like the concept, but that could be a nightmare to implement > as it's hard to tell if it's a class reference or a constant enclosed > in () for the parser. And seeing as you can have a constant with the > same name as a class, which should take precedence? > > 4. Should __toString still be called for string contexts? Or would > the presence of __castTo then negate the existance of __toString. So > if you don't implement __castTo(), __toString() would still be called > for a string cast. But if you do, __castTo would be called instead... > It would then work for backwards compatibility, while enabling > __toString to be eventually deprecated in favor of __castTo (not for a > long time mind you, but eventually, possibly 6 or 7)... > > What do you think? > > Anthony > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > -- Laruence Xinchen Hui http://www.laruence.com/ -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php