1

I have some template files that have default arguments defined at the top of each file. I can't get type hinting for these values to work correctly; it just says there is no reference. I am including the WordPress core files in Intelephense, so it understands what a WP_Post is, I just can't get it to understanding typing on a multidimensional aray.

I found this GitHub issue which discusses a similar problem, and includes some suggestions on things to try. No matter which method I used, all I can get it to respond with for $args["post"] is `No references found for 'post'".

Eventually, I found this WordPress forums thread discussing a similar issue, and links to this WordPress core file which includes the "WordPress-y" way to do document multidimensional arrays, but even this still results in the same message.

That's how I've gotten to this point, but this doesn't seem to be working correctly either, because the reference pop-up looks quite odd (screenshot below), and doesn't seem to do anything for type hinting.

<?php
/**
 * @var array $args {
 *     @type WP_Post $post,
 *     @type string  $class,
 *     @type bool    $light,
 *     @type string  $title,
 *     @type bool    $meta,
 *     @type string  $content,
 * }
 */
$args = array_merge([
    "post"    => null,
    "class"   => "",
    "light"   => false,
    "title"   => "",
    "meta"    => null,
    "content" => "",
], $args);

/**
 * Retrieve values based on `$post` if set
 */
if ($args["post"] instanceof WP_Post) {
    /**
     * Set title
     */
    if ($args["title"] === "") {
        $args["title"] = apply_filters("the_title", $args["post"]->post_title, $args["post"]->ID);
    }

    /**
     * Set meta based on post type
     */
    if ($args["meta"] === null && $args["post"]->post_type === "post") {
        $args["meta"] = true;
    }

    /**
     * Set content
     */
    if ($args["content"] === "") {
        $args["content"] = apply_filters("the_content", $args["post"]->post_content);
    }
}
?>

reference pop up showing contents of the comment at the top of previous code block

reference pop up for $args["post"] showing "No references found"

Also, I understand that perhaps a class structure would be better, and I will look in to that, but that entails retooling our templating system, so that will take time. For now, I'd like to get type hinting working in this use if at all possible.

JacobTheDev
  • 17,318
  • 25
  • 95
  • 158

4 Answers4

1

First, you can always convince most of the linters what the variable type is by use of @var annotation:

/** @var array $foo */
$foo = $bar->get();

BUT before you so, please ensure WHY it sees null|string[]|string|false and not object in the first place. It might be a bug indication or incorrect PHPDocs elsewhere, but usually if Intelisense cannot tell what it is precisely, it would show mixed - your is more precise, so check why. But that is for linter only and makes no difference at runtime. Also, if it is null by default typehinting as object would be incorrect. It's ?object then.

As for accessing $args["post"] - there's no fancy magic you can pull - you either check for null prior calling, or use ?-> syntax to not call on null (if you use PHP that supports that).

Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
  • Thanks, that `?->` helped, but now I'm seeing even weirder behavior. I've updated my original question. I'll try to look in to where that `null|string[]|string|false` is coming from, but as far as I'm aware I'm only running `WP_Post`s through this. – JacobTheDev Apr 12 '23 at 20:53
0

I'm not sure what the support is like in Intelephense but you could try using array shapes which are widely supported by tools like Psalm, PHPStan, Phan and PhpStorm.

Example:

/** @var array{ post: ?WP_Post, class: string, light: bool, title: string, meta: ?bool, content: string } $args */
$args = array_merge([
    "post"    => null,
    "class"   => "",
    "light"   => false,
    "title"   => "",
    "meta"    => null,
    "content" => "",
], $args);

More info here: https://phpstan.org/writing-php-code/phpdoc-types#array-shapes

George
  • 2,860
  • 18
  • 31
0

The error message "No references found for 'post'" is likely being caused by the @var annotation in the code.

The @var annotation is used to specify the variable type for documentation purposes, but it does not actually define the variable. The error message indicates that the post variable is not defined or referenced anywhere in the code.

To fix the error, you need to define the $post variable or remove the @var annotation for post.

If you intend to use the $post variable in your code, you can define it like this:

$post = get_post(); // or some other method of getting a WP_Post object

Then, you can pass it as a value for the post key in the $args array:

$args = [
    "post" => $post,
    // other properties
];

Alternatively, if you don't need the @var annotation, you can simply remove it:

/**
 * @var array $args {
 *     @type string  $class,
 *     @type bool    $light,
 *     @type string  $title,
 *     @type bool    $meta,
 *     @type string  $content,
 * }
 */
$args = array_merge([
    "post"    => null,
    "class"   => "",
    "light"   => false,
    "title"   => "",
    "meta"    => null,
    "content" => "",
], $args);

This will remove the error message and should not affect the functionality of the code.

Xaib Aslam
  • 91
  • 6
0

You already answer the question: "I understand that perhaps a class structure would be better".

Normally in programming an array is a collection. But in PHP an array works like a collection or hash map.

If you use an array as a collection, an annotation like @var Post[] will work. In another hand, you can't type the array keys (hash map).

The PSR-5 propose things like: ArrayObject, ArrayObject<int, string> and ArrayObject<ArrayObject>

But not ArrayObject {post: Post, val: Int}

The solution is to replace the array with a class. And frankly, replacing $data["post"] by $object->post is not a big deal.