29

I am trying to figure out if it is possible to use PHPdoc to define the object properties being returned by a function or a object method.

Say I have the following class:

class SomeClass {
    public function staffDetails($id){

        $object = new stdClass();
        $object->type = "person";
        $object->name = "dave";
        $object->age = "46";        

        return $object;
    }
}

Now, it is easy enough to define input parameters.

 /**
 * Get Staff Member Details
 * 
 * @param   string  $id    staff id number
 * 
 * @return  object
 */

class SomeClass {
    public function staffDetails($id){
        $object = new stdClass();
        $object->type = "person";
        $object->name = "dave";
        $object->age = "46";        

        return $object;
    }
}

The question is is there a similar thing for defining properties of the output object (of a stdClass) returned by the method in question. So that another programmer does not have to open this class and manually look into the method to see what the return object is returning?

Yevgeniy Afanasyev
  • 37,872
  • 26
  • 173
  • 191
someuser
  • 2,279
  • 4
  • 28
  • 39
  • 8
    Why don't you just have a StaffDetails class with type,name and age properties? Then you can use @param StaffDetails – Ken Sep 15 '12 at 08:00
  • 2
    if you dont want to make a concrete type for the stdClass you can still write `@return \stdClass holding type, name and age` or explain so in the long description of the Doc Block. At least it's documented then. That won't make your IDE magically know the properties though. – Gordon Sep 15 '12 at 08:08
  • no - I dont want the IDE to know the properties. I just would like them nicely documented. The object I am actually using has about 40 variables within it so I really wanted to know if the was a way to lay them out nicely in a table like input parameters appear. Otherwise if just using a long description it gets messy and hard to read. – someuser Sep 15 '12 at 08:12
  • 1
    @l_t Well, you can always document them in the DocBlock's Long Description. But an object having 40 variables is a good indicator for an object knowing too much anyway. You can likely split that object into 4 to 10 individual objects. Look out for properties that can be grouped. Extract them into their own class. Associate the main class with that class then, so you'll get a nice dedicated object graph in the end. – Gordon Sep 15 '12 at 08:21
  • @Gordon Thanks- The method in question is a grouping of many different classes. I did it like this so the front end developer can just call one class method and get an object back with all the cleaned / pre-processed data back needed for that page (in this case product data). Is that generally not a good idea? – someuser Sep 15 '12 at 08:37
  • @l_t I see. You turned your object graph into a Data Transfer Object. That's a valid approach. You could still [give it a type though, e.g. `ProductDetails`](http://qafoo.com/blog/016_struct_classes_in_php.html) and then either document it by giving it public properties or by adding [@property annotations](http://www.phpdoc.org/docs/latest/for-users/tags/property.html) – Gordon Sep 15 '12 at 09:13
  • @artlung Are you asking for the `@return` for the class? Do we both on the same page? Class can have any number of methods which can return any type results. – Alex Oct 10 '18 at 17:50
  • @Alex An alternative to `@return stdClass` whereby the members of that class are enumerated. – artlung Oct 10 '18 at 18:10
  • @artlung to me it is still unclear, probably you should better set another question on SO and clarify what exactly is your expectations. – Alex Oct 10 '18 at 18:23
  • @Alex I appreciate that, but I really do think this question asks the question pretty fully. I'll think about how I'd form the question differently and consider it. – artlung Oct 10 '18 at 18:39
  • I have it answered here https://stackoverflow.com/questions/65946033/php-docblock-for-json-decode-d-objects/65946832#65946832 – Yevgeniy Afanasyev Jan 28 '21 at 23:45

5 Answers5

15

Here it is 4 years later, and there still does not appear to be a way to annotate the properties of a stdClass object as originally described in your question.

Collections had been proposed in PSR-5, but that appears to have been shot down: https://github.com/php-fig/fig-standards/blob/211063eed7f4d9b4514b728d7b1810d9b3379dd1/proposed/phpdoc.md#collections

It seems there are only two options available:

Option 1:

Create a normal class representing your data object and annotate the properties.

class MyData
{
    /**
     * This is the name attribute.
     * @var string
     */
    public $name;

    /**
     * This is the age attribute.
     * @var integer
     */
    public $age;
}

Option 2:

Create a generic Struct type class as suggested by Gordon and extend it as your data object, using the @property annotation to define what generic values are possible to access with __get and __set.

class Struct
{
    /**
     * Private internal struct attributes
     * @var array
     */
    private $attributes = [];

    /**
     * Set a value
     * @param string $key
     * @param mixed $value
     */
    public function __set($key, $value)
    {
        $this->attributes[$key] = $value;
    }

    /**
     * Get a value
     * @param string $key
     * @return mixed
     */
    public function __get($key)
    {
        return isset($this->attributes[$key]) ? $this->attributes[$key] : null;
    }

    /**
     * Check if a key is set
     * @param string $key
     * @return boolean
     */
    public function __isset($key)
    {
        return isset($this->attributes[$key]) ? true : false;
    }
}

/**
 * @property string $name
 * @property integer $age
 */
class MyData extends Struct
{
    // Can optionally add data mutators or utility methods here
}
Community
  • 1
  • 1
Jeremy Harris
  • 24,318
  • 13
  • 79
  • 133
  • 1
    If you go with option 1, you can declare the class in a file scanned by your IDE but ignored by your project. State that the method returns a `StaffMember`, but keep using `stdClass` in the implementation. – David Harkness Apr 06 '17 at 18:59
  • How can you have a file scanned by your IDE but ignored by your project with NetBeans? – Yevgeniy Afanasyev Jan 28 '21 at 23:59
  • This is an old question -- I would recommend asking a new one. – Jeremy Harris Feb 01 '21 at 15:30
  • It might also be a good idea to implement the [Serializable](https://www.php.net/manual/en/class.serializable.php) and [JsonSerializable](https://www.php.net/manual/en/jsonserializable.jsonserialize.php) interface – Tofandel Aug 18 '22 at 09:52
8

You have only two way to document the structure of the result class.

1.One can describe the structure in a comment text. For example:

class SomeClass 
{
    /**
     * Getting staff detail.
     * Result object has following structure:
     * <code>
     * $type - person type
     * $name - person name
     * $age - person age
     * </code>
     * @param string $id staff id number
     *
     * @return stdClass
     *
     */
    public function staffDetails($id){
        $object = new stdClass();
        $object->type = "person";
        $object->name = "dave";
        $object->age = "46";
        return $object;
    }
}

2.One can create a data type that will inheritance stdClass and it will have an annotation of a result object. For example:

/**
 * @property string $type Person type
 * @property string $name Person name
 * @property integer $age Person age
 */
class DTO extends stdClass
{}

And use it in your other classes

class SomeClass {

    /**
     * Getting staff detail.
     *
     * @param string $id staff id number
     *
     * @return DTO
     *
     */
    public function staffDetails($id){

        $object = new DTO();
        $object->type = "person";
        $object->name = "dave";
        $object->age = "46";

        return $object;
    }
}

In my opinion, this way is better than a description in the text comment because it makes the code more obvious

Maksym Fedorov
  • 6,383
  • 2
  • 11
  • 31
6

If you are using PHP 7, you can define anonymous class.

class SomeClass {
    public function staffDetails($id){
        $object = (new class() extends stdClass {
                public /** @var string  */ $type;
                public /** @var string  */ $name;
                public /** @var int     */ $age;
            });

        $object->type = "person";
        $object->name = "dave";
        $object->age  = 46;        

        return $object;
    }
}

It is working for my IDE (tested in NetBeans)

Yevgeniy Afanasyev
  • 37,872
  • 26
  • 173
  • 191
1

The hack I use for autocomplete in PhpStorm:

  1. Create some meta file which will contain some classes to describe your structures. The file is never included and structures have their own name rules in order not to mess them with real existing classes:
<?php
/*
meta.php
never included
*/

/**
 * @property string $type
 * @property string $name
 * @property string $age
 */
class StaffDetails_meta {}
  1. Use the meta class as a return value in your real code PHPDoc:
<?php
/*
SomeClass.php
eventually included
*/

class SomeClass
{
    
    /**
     * Get Staff Member Details
     * 
     * @param   string  $id    staff id number
     * 
     * @return StaffDetails_meta
     */
    public function staffDetails($id)
    {
        $object = new stdClass();
        $object->type = "person";
        $object->name = "dave";
        $object->age = "46";        

        return $object;
    }
}
  1. Congratulations, this will make your IDE autocomplete your code when you'd typing something like (new SomeClass)->staffDetails('staff_id')->

P.S.: I know, almost 10 years passed but still actual

0

With for example json_decode it's harder to use own classes instead of stdClass, but in my case I just created dummy file with class definitions, which really isn't loaded and I'm adding own classes as @return (works for intelephense on vscode).

PHPdocObjects.php

/**
 * class only for PHPdoc (do not include)
 */
class Member {
    /** @var string */
    public $type;
    /** @var string */
    public $name;
    /** @var string */
    public $age;
}

/**
 * Other format
 *
 * @property string $type;
 * @property string $name;
 * @property string $age;
 */
class MemberAlt {}

SomeClass.php

 /**
 * Get Staff Member Details
 * 
 * @param   string  $id    staff id number
 * 
 * @return  Member  I'm in fact stdClass
 */

class SomeClass {
    public function staffDetails($id){
        $object = json_decode('{"type":"person","name":"dave","age":"46"}');
        return $object;
    }
}
Krzysiek
  • 2,494
  • 16
  • 20