On Sun, Feb 26, 2012 at 10:57 PM, Anthony Ferrara <[email protected]> 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