PHP 7 and Strict "Resource" Types

PHP 7 and strict resource types

PHP does not have a type hint for resources because

No type hint for resources is added, as this would prevent moving from resources to objects for existing extensions, which some have already done (e.g. GMP).

However, you can use is_resource() within the function/method body to verify the passed argument and handle it as needed. A reusable version would be an assertion like this:

function assert_resource($resource)
{
if (false === is_resource($resource)) {
throw new InvalidArgumentException(
sprintf(
'Argument must be a valid resource type. %s given.',
gettype($resource)
)
);
}
}

which you could then use within your code like that:

function test($ch)
{
assert_resource($ch);
// do something with resource
}

PHP 7: use both strict and non-strict type hinting?

Indeed, you can mix and match to your heart's content, in fact the feature was specifically designed to work that way.

declare(strict_types=1); isn't a language setting or configuration option, it's a special per-file declaration, a bit like namespace ...;. It only applies to the files you use it in, it won't affect other files.

So, for example:

<?php // math.php

declare(strict_types=1); // strict typing

function add(float $a, float $b): float {
return $a + $b;
}

// this file uses strict typing, so this won't work:
add("1", "2");

<?php // some_other_file.php

// note the absence of a strict typing declaration

require_once "math.php";

// this file uses weak typing, so this _does_ work:
add("1", "2");

Return typing works the same way. declare(strict_types=1); applies to function calls (NOT declarations) and return statements within a file. If you don't have a declare(strict_types=1); statement, the file uses "weak typing" mode.

What is the typed property for Resource

Short answer:

You can't. Sorry.

Some background:

There's an RFC here discussing the gap, but it hasn't moved since 2015: https://wiki.php.net/rfc/resource_typehint

The original RFC for scalar type hints specified that

No type declaration for resources is added, as this would prevent moving from resources to objects for existing extensions, which some have already done (e.g. GMP).

There's a comment on bug 71518 making the point that type-hinting for a resource really isn't very useful, since you'd still be able to pass in a file handle, or a GD resource, or a CURL handle, none of which do remotely the same thing. The bug itself has been suspended, so it doesn't look like this is going to be addressed any time soon.

A user-land compromise could be to write a thin object-wrapper around whichever resource type you need, and type-hint against that class instead. You still won't get typed property support for the resource on your new object, but it makes the issue less visible to the rest of your application.

PHP 8: Assign resource as property, parameter, or return type

No, you cannot type hint with resource.

Here's an RFC from 2015 where it was brought up, here's the PR with the implementation, and here's a thread of discussion on it.

The gist is that the PHP community wants to get rid of resources because they represent an older way of doing things. Also, resource is too generic, basically equivalent to object that it doesn't provide much, if any benefit.

From the discussion:

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

Andrea Faulds

And

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.

...

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.

Nikita Popov

Why does PHP strict typing allow function arguments of wrong type?

strict_types only affects function calls within the file in which it's declared. From the PHP docs:

Note:
Strict typing applies to function calls made from within the file with strict typing enabled, not to the functions declared within that file. If a file without strict typing enabled makes a call to a function that was defined in a file with strict typing, the caller's preference (coercive typing) will be respected, and the value will be coerced.

In your case, the examples are not calling the callback itself, they are passing it as an argument for array_map, meaning that wherever the function array_map is implemented, it has preference for coercive typing when array_map is calling your callback.

A possible solution to this would be to wrap array_map and make the call to your callback in a file in which strict_types is declared, such as this:

<?php
declare(strict_types=1);

$ids = ['1', '2', '3'];

function strict_array_map($fn, $arr){
return array_map(fn (...$arguments) => $fn(...$arguments), $arr);
}

// Now TypeError is thrown correctly
strict_array_map(fn (int $id) => $id, $ids);

// Throws PHP Fatal error: Uncaught TypeError: Return value of {closure}() must be of the type int, string returned
strict_array_map(fn ($id): int => $id, $ids);

https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.strict

Is there a guaranteed file resource on PHP?

php://memory should be universally available.

Typehinting for filehandle as argument in function

Unfortunately, you cannot use the primitive type resource as a type hint. The latest type hint system change to PHP, scalar type hints, only added int, float, string, and bool.

The error you quote has come up before as confusing, especially in the context of the scalar type hints. Let me template it for you:

Argument [N] passed to [Function] must be an instance of [Class], [Type] given

The confusion arises because PHP allows classes to have the same name as documented primitives (bool, float, etc.) for all primitives before PHP 7, and for some in PHP 7 and later
. So when you say stream $handle, PHP is expecting $handle to be of class stream. Likewise resource $handle expects $handle to be of class resource.

If you want to type hint resources, I suggest using an \SplFileObject:

$handle = new \SplFileObject('myfile.csv', 'r');
function parseHandle(\SplFileObject $handle) { ... }

This is not the best thing in the world, as \SplFileObject has a few quirks, but at the end of the day, if you want to type hint it in PHP, you must either have an array, a scalar, or a class.

With strict types enabled, array_map converts types anyways

It's not a bug (hat tip to Room 11 for pointing me in the right direction)

Here's the Strict Types RFC. It's really, really long and the most contentious RFC in the history of PHP (and I'm being serious). Here's the relevant portions cut out for you

This proposal builds in weak type checking by default (using the same rules), for internal and user functions.

A significant portion of the PHP community appears to favor fully-strict types. However, adding strictly type-checked scalar type declarations would cause a few problems:

Existing code which (perhaps unintentionally) took advantage of PHP's weak typing would break if functions it calls added scalar type declarations to parameters. This would complicate the addition of scalar type declarations to the parameters of functions in existing codebases, particularly libraries.

So this isn't a bug. This was part of the grand compromise that made this possible (baby steps towards stricter typing, if you will). Functions ignore strict typing. Yes, it's inconsistent with other languages (a fact the RFC notes in detail), but that's how the PHP community decided it should be for now.



Related Topics



Leave a reply



Submit