Structs data type in php?

后端 未结 7 1354
悲哀的现实
悲哀的现实 2020-12-07 17:47

Can anyone give me example for structs data type in php ? How come there is something like structs in php all of a sudden ?

7条回答
  •  醉梦人生
    2020-12-07 17:57

    Only associative arrays are structs in PHP.

    And you can't make them strict on their own.

    But you can sort of fake structure strictness with classes and interfaces, but beware that unlike structures, class instances are not passed in arguments, their identifiers are!


    You can define a struct through an interface (or at least close to it)

    Structs enforce a certain structure on an object.

    PHP (<= 7.3) does not have native structs, but you can get around it with interfaces and type hinting:

    interface FooStruct 
    {
        public function name() : string;
    }
    interface BarStruct 
    {
        public function id() : int;
    }
    interface MyStruct 
    {
       public function foo() : FooStruct;
       public function bar() : BarStruct;
    }
    

    Any class implementing MyStruct will be a MyStruct.

    The way it's build up is not up to the struct, it just ensures that the data returned is correct.


    What about setting data?

    Setting struct data is problematic as we end up with getters and setters and it's something that is close to an anemic object or a DTO and is considered an anti-pattern by some people

    Wrong example:

    interface FooStruct 
    {
        public function getName() : string;
        public function setName(string $value) : FooStruct;
    }
    interface BarStruct 
    {
        public function getId() : int;
        public function setId(int $value) : BarStruct;
    }
    interface MyStruct 
    {
       public function getFoo() : FooStruct;
       public function setFoo(FooStruct $value) : MyStruct;
       public function getBar() : BarStruct;
       public function setBar(BarStruct $value) : MyStruct;
    }
    

    Then we end up with class implementations that might be mutable, and a struct must not mutate, this is to make it a "data type", just like int, string. Yet there's no way to restrict that with interfaces in PHP, meaning people will be able to implement your struct interface in a class that is not a struct. Make sure to keep the instance immutable

    Also a struct may then be instantiated without the correct data and trigger errors when trying to access the data.

    An easy and reliable way to set data in a PHP struct class is through its constructor

    interface FooStruct 
    {
        public function name() : string;
    }
    interface BarStruct 
    {
        public function id() : int;
    }
    interface MyStruct 
    {
       public function foo() : FooStruct;
       public function bar() : BarStruct;
    }
    
    class Foo implements FooStruct 
    {
       protected $name;
       public function __construct(string $name)
       {
           $this->name = $name;
       }
       public function name() : string
       {
           return $this->name;
       }
    }
    
    class Bar implements BarStruct 
    {
       protected $id;
       public function __construct(string $id)
       {
           $this->id = $id;
       }
       public function id() : int
       {
           return $this->id;
       }
    }
    
    class My implements MyStruct 
    {
       protected $foo, $bar;
       public function __construct(FooStruct $foo, BarStruct $bar)
       {
           $this->foo = $foo;
           $this->bar = $bar;
       }
       public function foo() : FooStruct
       {
           return $this->foo;
       }
       public function bar() : BarStruct
       {
           return $this->bar;
       }
    }
    

    Type hinting using interfaces: (if your IDE supports it)

    If you don't mind not having the strict type checking, then another way would be using interfaces or classes with comments for the IDE.

    /**
     * Interface My
     * @property Foo $foo
     * @property Bar $bar
     */
    interface My 
    {
    
    }
    
    /**
     * Interface Foo
     * @property string|integer $id
     * @property string $name
     */
    interface Foo 
    {
    
    }
    
    /**
     * Interface Bar
     * @property integer $id
     */
    interface Bar
    {
    
    }
    

    The reason to use interfaces instead of classes is for the same reason why interfaces exist in the first place, because then many classes with many implementations can have this same structure and each method/function that uses it will support every class with this interface.

    This depends on your IDE, so you might need to use classes instead or just live without it.

    Note: Remember that you have to validate/sanitize the data in the instance elsewhere in the code to match the comment.

提交回复
热议问题