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

Reply via email to