# [Draft RFC] Object Casting and Assignment Handlers

- Thread: https://externals.io/message/58318
- Original archive: https://news-web.php.net/php.internals/58318
- Started by Anthony Ferrara on 2012-02-29T02:40:01+00:00
- Messages: 11
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #58318 — Anthony Ferrara — 2012-02-29T02:40:01+00:00

URL: https://externals.io/message/58318#58318

Hey all,

I've created a draft version of the RFC for implementing __castTo()
and __assign():

https://wiki.php.net/rfc/object_cast_magic

It's still a draft, and has a lot more work to do, but I figured this
would be enough to start triggering some discussion (or at least a
little bit more focused discussion).



One plea: Please keep this thread on-topic discussing the RFC and its
implications...

Thanks!

Anthony

---

## #58319 — Kris Craig — 2012-02-29T03:42:06+00:00

URL: https://externals.io/message/58318#58319 · In reply to: #58318

Agreed.  Discussion about type hinting/etc should remain on the other
topics.

Regarding this proposal, I need to look over it in more detail as I've only
just skimmed it.  But on a conceptual level at least, I think it definitely
has merit.

--Kris


On Tue, Feb 28, 2012 at 6:40 PM, Anthony Ferrara <ircmaxell@gmail.com>wrote:

> Hey all,
>
> I've created a draft version of the RFC for implementing __castTo()
> and __assign():
>
> https://wiki.php.net/rfc/object_cast_magic
>
> It's still a draft, and has a lot more work to do, but I figured this
> would be enough to start triggering some discussion (or at least a
> little bit more focused discussion).
>
>
>
> One plea: Please keep this thread on-topic discussing the RFC and its
> implications...
>
> Thanks!
>
> Anthony

---

## #58320 — Stas Malyshev — 2012-02-29T07:48:07+00:00

URL: https://externals.io/message/58318#58320 · In reply to: #58318

Hi!

> Hey all,
>
> I've created a draft version of the RFC for implementing __castTo()
> and __assign():
>
> https://wiki.php.net/rfc/object_cast_magic

I think having cast method may have merits, though use cases where 
objects need to be converted to scalars that aren't string are very 
limited, and cases where they need to do so transparently are almost 
non-existent. I think what outlined in the RFC is a backdoor operator 
overloading, through rather complex and unobvious magic. My opinion is 
that outside of very limited number of cases (such as implementing 
complex numbers or matrix algebra - and how frequently would one need do 
that in PHP anyway?) operator overloading is way more trouble than it's 
worth and makes code nearly unreadable as you never know what exactly 
each operator does. For example, if($object) would have completely 
different semantics than before, for some objects but not other, and 
without any obvious clue to the user what it actually does - and all 
that to save couple of keystrokes on if($object->valid())?

Still, if there's a valid use case found, cast magic method and 
"unboxing" method may have merit. So far the cases outlined seem either 
too artificial and narrow for language-level functionality, or plain 
wrong (like SplFixedArray example - nothing in this proposal would 
enable it to work with sort, for example). But I do not exclude other 
cases can exist.

However, assignment overloading does not seem viable to me.
Also, I'm not sure how this is possible technically: $obj = {expression} 
is supposed to replace $obj with the result of the expression, not call 
methods on $obj. Doing otherwise would be huge change in the semantics, 
a complete no go. Also, it's impossible if $obj is not set - meaning, 
code $obj = 1 would mean totally different things depending on if $obj 
is set or not - again, not a good idea. It also does not cover many 
corner cases but I don't even want to go there since an idea to change 
semantics of the assignment seems very wrong to me in principle, so no 
need to go into the fine details.
-- 
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

---

## #58325 — Gustavo Lopes — 2012-02-29T08:48:08+00:00

URL: https://externals.io/message/58318#58325 · In reply to: #58320

On Wed, 29 Feb 2012 08:48:07 +0100, Stas Malyshev <smalyshev@sugarcrm.com>  
wrote:

> Hi!
>
> > […]
>
> I think having cast method may have merits, though use cases where  
> objects need to be converted to scalars that aren't string are very  
> limited, and cases where they need to do so transparently are almost  
> non-existent.

I can think of a few: bridges to foreign types (e.g. Java objects),  
SimpleXML like libraries and bigint objects, for instance. The RFC has  
more examples.

I think what outlined in the RFC is a backdoor operator
> overloading, through rather complex and unobvious magic. My opinion is  
> that outside of very limited number of cases (such as implementing  
> complex numbers or matrix algebra - and how frequently would one need do  
> that in PHP anyway?) operator overloading is way more trouble than it's  
> worth and makes code nearly unreadable as you never know what exactly  
> each operator does. For example, if($object) would have completely  
> different semantics than before, for some objects but not other, and  
> without any obvious clue to the user what it actually does - and all  
> that to save couple of keystrokes on if($object->valid())?

This is nothing like operator overloading -- it's much more limited in  
scope. Let's say you have two objects $a and $b. Then what this would  
allow would be $a + $b yielding a scalar like 5. Operator overloading  
would have that expression having the same effect as $a->operator+($b),  
which is much powerful. This effectively limits the scope of the feature  
to objects with make sense to treat as scalars and then effectively  
converts them to scalars in those circumstances.

> Still, if there's a valid use case found, cast magic method and  
> "unboxing" method may have merit. [...]
>
> However, assignment overloading does not seem viable to me.
> Also, I'm not sure how this is possible technically: $obj = {expression}  
> is supposed to replace $obj with the result of the expression, not call  
> methods on $obj. Doing otherwise would be huge change in the semantics,  
> a complete no go. [...]

Just like $a->foo = 'bar' is supposed to replace the 'foo' property of  
object? This ship sailed a long time ago.

That said, I at least agree that this should be handled with caution.  
Changing the 'set' handler seems more related with the 'boxing' part of  
the proposal (the one not in the RFC), and it's strange to find it here.

-- 
Gustavo Lopes

---

## #58329 — Stas Malyshev — 2012-02-29T09:32:18+00:00

URL: https://externals.io/message/58318#58329 · In reply to: #58325

Hi!

> I can think of a few: bridges to foreign types (e.g. Java objects),
> SimpleXML like libraries and bigint objects, for instance. The RFC has
> more examples.

This all can be (and is) done with engine-level hooks. As I noted in my 
previous mail, most RFC examples are either exotic (like limited-range 
integers) or wrong (like SplFixedArray). Bigint objects are a good case, 
but it won't work without proper operator overloading (as scalar + would 
not support all values) and operator overloading on PHP level is too 
dangerous. On engine level it may be viable, but that's another can of 
worms.

> This is nothing like operator overloading -- it's much more limited in
> scope. Let's say you have two objects $a and $b. Then what this would
> allow would be $a + $b yielding a scalar like 5. Operator overloading

So how it's not operator overloading? It changes semantics of + to do 
unobvious magic. Granted, the magic is limited, but it's still unobvious 
magic. Even then, I could probably see it being done, if there's some 
good use cases - meaning something that a) is needed by many users (not 
just "it's be cool if we could pull of this trick just for the fun of 
it") b) without it doing the same is substantially harder.

> Just like $a->foo = 'bar' is supposed to replace the 'foo' property of
> object? This ship sailed a long time ago.

No it did not. Overriding object access for some specific object to do 
set operation is one thing, changing semantics of a basic assignment 
operation is another. BTW, what exactly $a->foo = 'bar' supposed to do 
here according to RFC? Call __get and call __assign on the result or 
call __set? You see how this magic becomes unmanageable.

> That said, I at least agree that this should be handled with caution.

I would replace "caution" with "ten foot pole". I do not see how 
changing general semantics of assignment can lead to anything good. 
Especially in PHP where the code is supposed to be readable by 
relatively unsophisticated users (and yes, that means you should avoid 
"creative" get/sets too btw, but since most use cases do what user 
thinks they will we don't have a problem). When I can't know what $obj = 
1; does it's not a good idea.
-- 
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

---

## #58334 — Anthony Ferrara — 2012-02-29T12:59:58+00:00

URL: https://externals.io/message/58318#58334 · In reply to: #58320

Stas,

Thanks for the comments!

Replies inline:

Thanks,

Anthony


> Hi!
>
>
> > […]
>
>
> I think having cast method may have merits, though use cases where objects
> need to be converted to scalars that aren't string are very limited, and
> cases where they need to do so transparently are almost non-existent.

I've come across at least a few cases where it would be nice to be
able to do so.  Of course there are always workarounds to doing so,
but they require the target code to know about the object first.  This
creates a bit of coupling between disparate object trees.  Enabling
transparent conversion would further reduce coupling there for those
instances.

Furthermore, I think this is one of those cases where the potential is
hard to judge because it's not possible now...

> I think what outlined in the RFC is a backdoor operator overloading, through
> rather complex and unobvious magic. My opinion is that outside of very
> limited number of cases (such as implementing complex numbers or matrix
> algebra - and how frequently would one need do that in PHP anyway?) operator
> overloading is way more trouble than it's worth and makes code nearly
> unreadable as you never know what exactly each operator does.

Pedantic note: you never know what a method call does either unless
you look it up.  This functionality is on the class level, so the same
semantics apply here as well.  It's not like it's defined in a
function call (like spl_autoload), where it could be anywhere.  You
just need to check the class and tree to see what's happening.  I'm
not sure how that's significantly different than existing magic
methods in this case...

> For example, if($object) would have completely different semantics than before, for some
> objects but not other, and without any obvious clue to the user what it
> actually does - and all that to save couple of keystrokes on
> if($object->valid())?

I agree the if() case is a bit much.  It's just a happy accident that
the engine provides.

> Still, if there's a valid use case found, cast magic method and "unboxing"
> method may have merit. So far the cases outlined seem either too artificial
> and narrow for language-level functionality, or plain wrong (like
> SplFixedArray example - nothing in this proposal would enable it to work
> with sort, for example). But I do not exclude other cases can exist.

Correct, sort wouldn't work now.  But that's just because array
parameters to internal functions aren't cast.  That change could be
added to fully support this (just as other scalars are).

I'm not saying it should happen, but if it did, it would fully enable
something like splFixedArray to operate with native array parameter
functions...

> However, assignment overloading does not seem viable to me.
> Also, I'm not sure how this is possible technically: $obj = {expression} is
> supposed to replace $obj with the result of the expression, not call methods
> on $obj.

The engine already calls methods on $obj when that happens.  That's
the set handler.  It just happens that user classes have a null set
handler, which is why it works the way it does.  Internal classes have
full ability to work this way...

> Doing otherwise would be huge change in the semantics, a complete
> no go. Also, it's impossible if $obj is not set - meaning, code $obj = 1
> would mean totally different things depending on if $obj is set or not -
> again, not a good idea.

Pedantic note: It already means different things.  We have notices if
it's not set, and it behaves differently if references are involved.
So already we have a few different effects on what happens depending
on where and how $obj was defined.  So I fail to see how this is
*that* much of a shift.

The only thing this does change (which I admit is a bit weird) is the
ability for this to happen:

$a = 1;
$a !== 1;

>It also does not cover many corner cases but I don't
> even want to go there since an idea to change semantics of the assignment
> seems very wrong to me in principle, so no need to go into the fine details.

I guess I don't see it as such.  I can see the readability issues, but
really what it can enable is really powerful.  Additionally, the code
is already there, and there are already classes using that code
(SimpleXML for one).  So it's not like it's introducing new
functionality, it's just exposing the existing functionality to be
leveraged by PHP land code...



--- From Other Reply ---

> > […]
>
>
> This all can be (and is) done with engine-level hooks. As I noted in my
> previous mail, most RFC examples are either exotic (like limited-range
> integers) or wrong (like SplFixedArray). Bigint objects are a good case, but
> it won't work without proper operator overloading (as scalar + would not
> support all values) and operator overloading on PHP level is too dangerous.
> On engine level it may be viable, but that's another can of worms.

Well, why should we have to resort to writing PECL extensions for this
functionality?  If it's exposed to C code, and it's not dangerous to
expose to PHP land (meaning from an engine stability standpoint), why
not?

> > […]
>
>
> So how it's not operator overloading? It changes semantics of + to do
> unobvious magic. Granted, the magic is limited, but it's still unobvious
> magic. Even then, I could probably see it being done, if there's some good
> use cases - meaning something that a) is needed by many users (not just
> "it's be cool if we could pull of this trick just for the fun of it") b)
> without it doing the same is substantially harder.

Aren't __invoke and __set_state just as unobvious magic?  The reason
it's unobvious is that you don't realize what it's doing.  And that's
just because you haven't used it yet.  It really is quite straight
forward: If using the object in a scalar context, the cast method is
called to let the object determine how it should behave.

In fact, I think that's a hell of a lot more obvious than the current
result of $obj + 1...

> > […]
>
>
> No it did not. Overriding object access for some specific object to do set
> operation is one thing, changing semantics of a basic assignment operation
> is another. BTW, what exactly $a->foo = 'bar' supposed to do here according
> to RFC? Call __get and call __assign on the result or call __set? You see
> how this magic becomes unmanageable.

No, assign is only called when assigning to an object.  So __set would
be called in any case.  Than, only if the internal representation of
->foo assigned by __set() is an object that is overloaded assign, then
it would be assigned.

The existing magic methods still work just as they ever did.  If foo
is a public object, then __assign would be called there.  if it's not,
then __set would be called.

I definitely can see your point, I just don't think it's nearly as
severe as you're making it...


> > […]
>
>
> I would replace "caution" with "ten foot pole". I do not see how changing
> general semantics of assignment can lead to anything good.

Umm, those already happen.  This isn't changing the semantics of
assignment.  It's just exposing functionality that's already available
at the engine level to PHP code...

> Especially in PHP
> where the code is supposed to be readable by relatively unsophisticated
> users (and yes, that means you should avoid "creative" get/sets too btw, but
> since most use cases do what user thinks they will we don't have a problem).
> When I can't know what $obj = 1; does it's not a good idea.

PHP hasn't been readable by unsophisticated users for over a decade.
It already can do some very non-obvious things.  The big change here
is that `=` against a native variable is no longer a completely
binding operator (it hasn't been a completely binding operator for
properties and array indexes for a long time).

You already don't know what $obj->foo = 1 does.  And you don't know
what $obj['foo'] = 1; does...

I guess my point is that the same arguments you're making here can be
made against a large portion of functionality already in core (and
seen as powerful additions I might add).

And for me, the big reason to add it is for symmetry with casting...

> --
> Stanislav Malyshev, Software Architect
> SugarCRM: http://www.sugarcrm.com/
> (408)454-6900 ext. 227

---

## #58335 — Lazare Inepologlou — 2012-02-29T14:45:54+00:00

URL: https://externals.io/message/58318#58335 · In reply to: #58318

Hello Antony,

You did a nice work for the RFC.

However, I have to disagree with the name __assign, because it limits the
type casting operation only to assignments. An implicit  type casting could
very well happen upon calling a function with type hints.

Therefore, I would suggest the use of something like __castFrom(mixed
$value). Of course, this changes the semantics a little bit:
1. The function has to be static.
2. The function has to return the new object.

I would suggest to check out C# implicit casting, which does exactly this
thing (in compile-time however). Check this example:
http://msdn.microsoft.com/en-us/library/z5z9kes2.aspx

This way we don't mess up with the assignment operator. Meanwhile, there is
another interesting RFC under discussion (check the thread "Scalar Type
Hinting") which seems to be far more promising than overloading the
assignment operator.


Lazare INEPOLOGLOU
Ingénieur Logiciel


2012/2/29 Anthony Ferrara <ircmaxell@gmail.com>

> Hey all,
>
> I've created a draft version of the RFC for implementing __castTo()
> and __assign():
>
> https://wiki.php.net/rfc/object_cast_magic
>
> It's still a draft, and has a lot more work to do, but I figured this
> would be enough to start triggering some discussion (or at least a
> little bit more focused discussion).
>
>
>
> One plea: Please keep this thread on-topic discussing the RFC and its
> implications...
>
> Thanks!
>
> Anthony

---

## #58338 — Richard Lynch — 2012-02-29T17:16:08+00:00

URL: https://externals.io/message/58318#58338 · In reply to: #58318

> https://wiki.php.net/rfc/object_cast_magic

Suggestion:
Rename __castTo as __castObject, to be parallel to engine

Question:
Is there no need to implement the get() function in userland?
It "feels" wrong for 1/3 to be missing, but I probably just don't "get
it"

The const example seems quite contrived, given that a) it's allowed to
be unset() and b) PHP has `define()`

I believe that particular example weakens the RFC rather than
strengthens it.

Re: your conversation with Stas:
I have to agree with Stas.

In short, there is "complexity" and "complexity squared" and this just
seems like "complexity squared" for a handful of edge cases that only
provides syntactic sugar / less typing versus a new feature that is
needed to achieve a goal that currently can't be done.

If it made it possible to achieve the impossible, or even just
simplified your code without such a wide scope for abuse by people who
only think they know what they are doing...

-- 
brain cancer update:
http://richardlynch.blogspot.com/search/label/brain%20tumor
Donate:
https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FS9NLTNEEKWBE

---

## #58339 — Stas Malyshev — 2012-02-29T17:33:28+00:00

URL: https://externals.io/message/58318#58339 · In reply to: #58334

Hi!

> > […]
>
> The engine already calls methods on $obj when that happens.  That's
> the set handler.  It just happens that user classes have a null set
> handler, which is why it works the way it does.  Internal classes have
> full ability to work this way...

This is internal implementation detail. Having it in the guts of the 
engine is one thing, exposing it to the user is quite another. The 
engine can also access arbitrary memory addresses and write arbitrary 
data there, but we don't propose to let the user do the same in PHP.

> Pedantic note: It already means different things.  We have notices if
> it's not set, and it behaves differently if references are involved.
> So already we have a few different effects on what happens depending
> on where and how $obj was defined.  So I fail to see how this is
> *that* much of a shift.

Again, you seem to miss important differences here. Providing notices 
when something is wrong in the expression is one thing, changing 
semantics of assignment is quite another. Saying "because we have 
notices it's also OK to have completely different semantics" makes very 
little sense to me.

> really what it can enable is really powerful.  Additionally, the code
> is already there, and there are already classes using that code
> (SimpleXML for one).  So it's not like it's introducing new
> functionality, it's just exposing the existing functionality to be
> leveraged by PHP land code...

SimpleXML does not change semantics of assignment. It uses some engine 
trickery to achieve what it does but the semantics exposed to the user 
is simple and intuitive. You propose to create ability to introduce 
semantics which in its intended usage will be both counterintuitive and 
disagreeing with how the engine works now.

-- 
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

---

## #58374 — Clint M Priest — 2012-03-01T00:45:19+00:00

URL: https://externals.io/message/58318#58374 · In reply to: #58320

As much as I would love to have __castTo() and __assign() I have to agree with Stas here that it fundamentally changes the mechanics of if($object) and unfortunately turns that simple if statement into a possible hour long hunt to find the code that is doing the damage, if it is even considered a possibility by someone reading the code.

For the record, I really have only ever needed something like __toArray() so that objects implementing ArrayAccess could be passed to array internal functions.

I am interested in object natives though, which this is leading in the direction of.

-Clint

-----Original Message-----
From: Stas Malyshev [mailto:smalyshev@sugarcrm.com] 
Sent: Wednesday, February 29, 2012 1:48 AM
To: Anthony Ferrara
Cc: internals@lists.php.net
Subject: Re: [PHP-DEV] [Draft RFC] Object Casting and Assignment Handlers

Hi!

> Hey all,
>
> I've created a draft version of the RFC for implementing __castTo() 
> and __assign():
>
> https://wiki.php.net/rfc/object_cast_magic

I think having cast method may have merits, though use cases where objects need to be converted to scalars that aren't string are very limited, and cases where they need to do so transparently are almost non-existent. I think what outlined in the RFC is a backdoor operator overloading, through rather complex and unobvious magic. My opinion is that outside of very limited number of cases (such as implementing complex numbers or matrix algebra - and how frequently would one need do that in PHP anyway?) operator overloading is way more trouble than it's worth and makes code nearly unreadable as you never know what exactly each operator does. For example, if($object) would have completely different semantics than before, for some objects but not other, and without any obvious clue to the user what it actually does - and all that to save couple of keystrokes on if($object->valid())?

Still, if there's a valid use case found, cast magic method and "unboxing" method may have merit. So far the cases outlined seem either too artificial and narrow for language-level functionality, or plain wrong (like SplFixedArray example - nothing in this proposal would enable it to work with sort, for example). But I do not exclude other cases can exist.

However, assignment overloading does not seem viable to me.
Also, I'm not sure how this is possible technically: $obj = {expression} is supposed to replace $obj with the result of the expression, not call methods on $obj. Doing otherwise would be huge change in the semantics, a complete no go. Also, it's impossible if $obj is not set - meaning, code $obj = 1 would mean totally different things depending on if $obj is set or not - again, not a good idea. It also does not cover many corner cases but I don't even want to go there since an idea to change semantics of the assignment seems very wrong to me in principle, so no need to go into the fine details.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

---

## #58406 — jpauli — 2012-03-01T10:40:04+00:00

URL: https://externals.io/message/58318#58406 · In reply to: #58374

> As much as I would love to have __castTo() and __assign() I have to agree
> with Stas here that it fundamentally changes the mechanics of if($object)
> and unfortunately turns that simple if statement into a possible hour long
> hunt to find the code that is doing the damage, if it is even considered a
> possibility by someone reading the code.
>
> For the record, I really have only ever needed something like __toArray()
> so that objects implementing ArrayAccess could be passed to array internal
> functions.
>

In my own advice, this is far more important than every other thing, really.
That could require adding __toArray() to ArrayAccess, which would BC break,
but that has to be discussed. Why not another RFC about that ?

Also, one should keep the past decisions in his head, thus a refreshing
about ArrayAccess and current status could be good.
Please, see
http://devzone.zend.com/1124/zend-weekly-summaries-issue-361/#Heading3
http://devzone.zend.com/284/zend-weekly-summaries-issue-211/#Heading5  for
example.

My thoughts

Julien.P



>
> I am interested in object natives though, which this is leading in the
> direction of.
>
> -Clint
>
> -----Original Message-----
> From: Stas Malyshev [mailto:smalyshev@sugarcrm.com]
> Sent: Wednesday, February 29, 2012 1:48 AM
> To: Anthony Ferrara
> Cc: internals@lists.php.net
> Subject: Re: [PHP-DEV] [Draft RFC] Object Casting and Assignment Handlers
>
> Hi!
>
> > […]
>
> I think having cast method may have merits, though use cases where objects
> need to be converted to scalars that aren't string are very limited, and
> cases where they need to do so transparently are almost non-existent. I
> think what outlined in the RFC is a backdoor operator overloading, through
> rather complex and unobvious magic. My opinion is that outside of very
> limited number of cases (such as implementing complex numbers or matrix
> algebra - and how frequently would one need do that in PHP anyway?)
> operator overloading is way more trouble than it's worth and makes code
> nearly unreadable as you never know what exactly each operator does. For
> example, if($object) would have completely different semantics than before,
> for some objects but not other, and without any obvious clue to the user
> what it actually does - and all that to save couple of keystrokes on
> if($object->valid())?
>
> Still, if there's a valid use case found, cast magic method and "unboxing"
> method may have merit. So far the cases outlined seem either too artificial
> and narrow for language-level functionality, or plain wrong (like
> SplFixedArray example - nothing in this proposal would enable it to work
> with sort, for example). But I do not exclude other cases can exist.
>
> However, assignment overloading does not seem viable to me.
> Also, I'm not sure how this is possible technically: $obj = {expression}
> is supposed to replace $obj with the result of the expression, not call
> methods on $obj. Doing otherwise would be huge change in the semantics, a
> complete no go. Also, it's impossible if $obj is not set - meaning, code
> $obj = 1 would mean totally different things depending on if $obj is set or
> not - again, not a good idea. It also does not cover many corner cases but
> I don't even want to go there since an idea to change semantics of the
> assignment seems very wrong to me in principle, so no need to go into the
> fine details.
> --
> Stanislav Malyshev, Software Architect
> SugarCRM: http://www.sugarcrm.com/
> (408)454-6900 ext. 227
>
> --
>  To unsubscribe,
> visit: http://www.php.net/unsub.php
