Hi guys,
I just poked up an RFC and a patch for resource typehints and return
types. I'd really like to hear your thoughts about it!
RFC:
https://wiki.php.net/rfc/resource_typehint
Patch:
https://github.com/php/php-src/pull/1631
Cheers,
Ben Scholzen 'DASPRiD'
Community Review Team Member | mail@dasprids.de
Zend Framework | http://www.dasprids.de
Hi Ben
Ben Scholzen 'DASPRiD' wrote:
Hi guys,
I just poked up an RFC and a patch for resource typehints and return
types. I'd really like to hear your thoughts about it!
Anthony's Scalar Type Hinting with Cast RFC originally had a resource
type hint, but it was later removed, and subsequent RFCs have followed
its lead in not including a resource typehint.
The reason for this is that the resource type is an anachronism from an
age in which PHP did not have objects, yet still needed to make certain
types of data opaque. The resource type is a type that exists only to
shuffle around C pointers between internal functions. It has no semantic
value. Because resources are now redundant, given the existence of
objects, their time is running out, and they will be replaced at some
point. Adding a type declaration for resource would mean that code using
it would break if we replace any existing usage of resources with
objects, preventing migration away from resource.
So, I'm against this RFC.
Thanks.
--
Andrea Faulds
http://ajf.me/
The reason for this is that the resource type is an anachronism from an
age in which PHP did not have objects, yet still needed to make certain
types of data opaque. The resource type is a type that exists only to
shuffle around C pointers between internal functions. It has no semantic
value. Because resources are now redundant, given the existence of
objects, their time is running out, and they will be replaced at some
point. Adding a type declaration for resource would mean that code using
it would break if we replace any existing usage of resources with
objects, preventing migration away from resource.
I see, I didn't really know about this. Although right now, we still use
resources to pass around the fopen()
pointers. Do you mean that it is
planned to have a read/write object like we have in e.g. Python
(supplied by the open() function)?
--
Ben Scholzen 'DASPRiD'
Community Review Team Member | mail@dasprids.de
Zend Framework | http://www.dasprids.de
On Wed, Nov 11, 2015 at 3:29 AM, Ben Scholzen 'DASPRiD' mail@dasprids.de
wrote:
The reason for this is that the resource type is an anachronism from an
age in which PHP did not have objects, yet still needed to make certain
types of data opaque. The resource type is a type that exists only to
shuffle around C pointers between internal functions. It has no semantic
value. Because resources are now redundant, given the existence of
objects, their time is running out, and they will be replaced at some
point. Adding a type declaration for resource would mean that code using
it would break if we replace any existing usage of resources with
objects, preventing migration away from resource.I see, I didn't really know about this. Although right now, we still use
resources to pass around thefopen()
pointers. Do you mean that it is
planned to have a read/write object like we have in e.g. Python (supplied
by the open() function)?
The long term plan is to do transitions similar to the one which GMP
underwent: It uses GMP objects since PHP 5.6 and was using resources
previously. The API is still the same (procedural), but we could now add an
additional object-oriented one as well.
Before this transition can happen comprehensively, we will have to add
support for persistent objects.
In addition to what Andrea said (resource type hint causing issues should
we choose to migrate to objects), I also think that the resource type hint
provides relatively little value in itself. It only says that you are
accepting some resource. However, resources are many. Is this a file
handle? Is it a database connection? Is it a streaming hash context? It
doesn't tell.
"resource" would be the analogue of an abstract "object" typehint (rather
than a specific class/interface hint), which notably we do not have either
-- the cases where it would be useful, i.e. the cases where you are working
on arbitrary objects (or resources) are relatively few.
Nikita
Hi!
The reason for this is that the resource type is an anachronism from an
age in which PHP did not have objects, yet still needed to make certain
types of data opaque. The resource type is a type that exists only to
I think more specific reason is not that resource type is outdated, but
that resource is not really a type - it's a collection of types. Mysql
connection is a resource, and file is a resource, but they are certainly
not interchangeable. So typing a value as "resource" would not achieve
you much.
--
Stas Malyshev
smalyshev@gmail.com
Hi,
Le 13/11/2015 04:30, Stanislav Malyshev a écrit :
Hi!
The reason for this is that the resource type is an anachronism from an
age in which PHP did not have objects, yet still needed to make certain
types of data opaque. The resource type is a type that exists only to
I think more specific reason is not that resource type is outdated, but
that resource is not really a type - it's a collection of types. Mysql
connection is a resource, and file is a resource, but they are certainly
not interchangeable. So typing a value as "resource" would not achieve
you much.
I agree. Some resources may disappear in the future but others, like
opened streams, are not obsolete at all.
As 'resource' is not specific enough. What about including the resource
type in some way ? Something like '@stream', '[stream]', '{stream}' ?
Just need to replace spaces with underscores (e.g. 'persistent_stream').
Regards
François
Am 13.11.2015 um 11:57 schrieb François Laupretre francois@php.net:
Hi,
Le 13/11/2015 04:30, Stanislav Malyshev a écrit :
Hi!
The reason for this is that the resource type is an anachronism from an
age in which PHP did not have objects, yet still needed to make certain
types of data opaque. The resource type is a type that exists only to
I think more specific reason is not that resource type is outdated, but
that resource is not really a type - it's a collection of types. Mysql
connection is a resource, and file is a resource, but they are certainly
not interchangeable. So typing a value as "resource" would not achieve
you much.I agree. Some resources may disappear in the future but others, like opened streams, are not obsolete at all.
As 'resource' is not specific enough. What about including the resource type in some way ? Something like '@stream', '[stream]', '{stream}' ? Just need to replace spaces with underscores (e.g. 'persistent_stream').
Regards
François
The alternative is replacing the resources by proper objects, without methods and public properties.
Then we could integrate it into our object hierarchy in a very lightweight way with proper typing.
Having special syntax doesn't really improve it much...
Bob
The alternative is replacing the resources by proper objects, without methods and public properties.
Then we could integrate it into our object hierarchy in a very lightweight way with proper typing.Having special syntax doesn't really improve it much...
Bob
I just looked at this again, and I don't know how I could miss this for
so long, but we already have SplFileObject. Wouldn't it make sense to
let fopen()
and complementary functions use that?
--
Ben Scholzen 'DASPRiD'
Community Review Team Member | mail@dasprids.de
Zend Framework | http://www.dasprids.de
Ben Scholzen 'DASPRiD' wrote on 23/11/2015 01:57:
The alternative is replacing the resources by proper objects, without
methods and public properties.
Then we could integrate it into our object hierarchy in a very
lightweight way with proper typing.Having special syntax doesn't really improve it much...
Bob
I just looked at this again, and I don't know how I could miss this
for so long, but we already have SplFileObject. Wouldn't it make sense
to letfopen()
and complementary functions use that?
I believe the blocker on just rushing to convert existing resources into
objects is that there are functions like is_resource()
and getttype()
which will start behaving differently.
Functions which accept a resource as a parameter could easily be
extended to accept either a resource or an object, but anything
currently returning a resource cannot be changed without declaring a
breaking change. And if you're changing fgets but not fopen, you might
as well just build a new API, which SplFileObject already has most of
(for some reason, it appears to include fputcsv but not fputs).
Regards,
Rowan Collins
[IMSoP]
Hi,
On Mon, Nov 23, 2015 at 10:30 AM, Rowan Collins rowan.collins@gmail.com
wrote:
Ben Scholzen 'DASPRiD' wrote on 23/11/2015 01:57:
The alternative is replacing the resources by proper objects, without
methods and public properties.
Then we could integrate it into our object hierarchy in a very
lightweight way with proper typing.Having special syntax doesn't really improve it much...
Bob
I just looked at this again, and I don't know how I could miss this for
so long, but we already have SplFileObject. Wouldn't it make sense to let
fopen()
and complementary functions use that?I believe the blocker on just rushing to convert existing resources into
objects is that there are functions likeis_resource()
and getttype() which
will start behaving differently.Functions which accept a resource as a parameter could easily be extended
to accept either a resource or an object, but anything currently returning
a resource cannot be changed without declaring a breaking change. And if
you're changing fgets but not fopen, you might as well just build a new
API, which SplFileObject already has most of (for some reason, it appears
to include fputcsv but not fputs).Regards,
Rowan Collins
[IMSoP]
How is this a breaking change? The only way you can get a resource, or
resource-object is from a function that currently returns a resource (e.g.
imagecreate()
), and you can't do anything with a resource except pass into
things that expect resources. If instead they return an object, and every
function that currently expects a resource now expects that kind of
resource-object, it could just work…
Would it be possible to create a (possibly empty, but maybe useful)
interface that all of the new resource-objects implement, meaning
is_resource()
and gettype()
can check for that going forward and return a
BC result (and if necessary, leave the current implementation in there as a
code path for custom extensions maybe). You could also type hint off that
interface, either transparently replacing the proposed type hint, or
instead of.
But I would definitely prefer to see a CurlResource or ImageResource object
instead of a resource type hint. Think:
class CurlResource implements Resource { }
function makeRequest(CurlResource $curl) { }
function serializeResource(Resource $resource) { }
gettype($myResource) == 'resource'
is_resource($myResource) == true
($myResource instanceof CurlHandler) == true
The only thing I see as contentious, is actually, is_object()
— should that
return false, maintaining BC, or true?
Davey Shafik wrote on 23/11/2015 16:17:
How is this a breaking change? The only way you can get a resource, or
resource-object is from a function that currently returns a resource
(e.g.imagecreate()
), and you can't do anything with a resource except
pass into things that expect resources. If instead they return an
object, and every function that currently expects a resource now
expects that kind of resource-object, it could just work…
Within those functions, it's fine, but there are a handful of "meta"
functions which can tell the difference between a resource and an
object, and these may be used in existing code for error handling or
switching behaviour - e.g.
switch ( gettype($file) )
{
case 'string':
// code to open a new handle
break;
case 'resource':
// code to use the open handle
break;
case 'object'
if ( $file instanceOf MyFileWrapperInterface ) // ...
break;
default:
// error
}
Would it be possible to create a (possibly empty, but maybe useful)
interface that all of the new resource-objects implement, meaning
is_resource()
andgettype()
can check for that going forward and
return a BC result (and if necessary, leave the current implementation
in there as a code path for custom extensions maybe). You could also
type hint off that interface, either transparently replacing the
proposed type hint, or instead of.
This certainly helps, but you've still got to break something, because
currently is_resource()
and is_object()
are mutually exclusive, and
gettype()
can only return one string, so you've got to break somebody's
code somewhere. (Cue xkcd "every change breaks somebody's flow" comic;
but I think the example above demonstrates that this is a non-trivial
break.)
But I would definitely prefer to see a CurlResource or ImageResource
object instead of a resource type hint.
Definitely agree here.
The only thing I see as contentious, is actually,
is_object()
— should
that return false, maintaining BC, or true?
I think it would be weird not to have it return true - otherwise in 10
years time, there'd be a weird note in the manual saying
"is_object($var): returns true if $var is an object, unless it is one of
the following internal types..." gettype()
returning 'resource' for an
object would be similarly surprising.
More contentious is how is_resource()
should behave; assuming all
resources are converted, it could just be deprecated anyway, I guess...
Regards,
Rowan Collins
[IMSoP]
I believe the blocker on just rushing to convert existing resources into
objects is that there are functions likeis_resource()
and getttype()
which will start behaving differently.
There's another blocker: the SplFileObject currently has no fclose()
method, which should definitely be implemented. Currently it relies on
being destroyed to close the internal resource. In case of cross
references, there's no way to explicitly close the file handle.
May I suggest to implement fclose()
in SplFileObject for now to bring it
in line with the plain functions? I'd say that when fclose()
was called
on an SplFileObject and e.g. an fwrite()
, fread()
or the like call is
made on the object, it throw's an exception?
--
Ben Scholzen 'DASPRiD'
Community Review Team Member | mail@dasprids.de
Zend Framework | http://www.dasprids.de
There's another blocker: the SplFileObject currently has no
fclose()
method, which should definitely be implemented. Currently it relies on
being destroyed to close the internal resource. In case of cross
references, there's no way to explicitly close the file handle.
Using reference counting and destructors as a mechanism for releasing resources is a very common OO pattern (sometimes referred to as "RAII"), and also used elsewhere in PHP, e.g. PDO.
It means that anywhere you have a reference to the object, you can actually use it, rather than having to check if it's been closed elsewhere, and saves the need for try..finally blocks in many places.
If you do want a weak reference, you can wrap it in a delegating container, with the "close and start throwing exceptions" behaviour you're after: just have a private member for the real resource, and pass through method calls only when it is not null.
Also note that circular references are not a big problem, as PHP has had a dedicated garbage collector built in for some time now, and you can normally limit their use with careful design.
Regards,
--
Rowan Collins
[IMSoP]