【问题标题】:Structs data type in php?在php中构造数据类型?
【发布时间】:2010-10-05 06:41:44
【问题描述】:

谁能给我 php 中 structs 数据类型的例子? php中怎么突然出现了structs之类的东西?

【问题讨论】:

  • 您是从哪里看到这些信息的? PHP 从来没有真正的struct 数据类型。
  • 请显示您阅读 PHP 结构的代码或链接。
  • 他在 var_dump-ed 一个肥皂对象时可能看到了 struct 这个词。
  • @ktm,你将this 称为结构吗?
  • @ktm 不幸的是,PHP 不支持 C/C++ 中的结构。所以你不能做这样的事情:class pseudostruct { (int) myint; (char) mychar; (string) mychar; } myObj = new pseudostruct;。如果 PHP 有这个特性会很棒,因为我们可以声明数据结构并希望读取数据并以非常简单和有效的方式为它们赋值,就像在 C 中一样。如果我们可以预先定义精确的内存也很棒变量的大小或使用 malloc。然后将数据读取到我的伪结构类的变量会很有趣!

标签: php


【解决方案1】:

最接近结构的是一个所有成员都公开的对象。

class MyStruct {
    public $foo;
    public $bar;
}

$obj = new MyStruct();
$obj->foo = 'Hello';
$obj->bar = 'World';

我会说看看PHP Class Documentation 是值得的。 如果您需要一次性结构,use the StdObject as mentioned in alex's answer

【讨论】:

  • 那将是 class MyStruct 而不是 object MyStruct ;)
  • “哎呀”在这里是适当的回应吗?教我在午休时间快速回答...
  • @ASpencer 感谢您也提到亚历克斯的回答。
  • 使用类代替结构是一个糟糕的选择。结构仅连接两个数据元素。类有额外的开销。例如,给定 Int 是一个 4 字节的内存区域,struct Location {x : Int, y : Int} 是 8 个字节。使用像 $x = 0, $y = 1, $location = [$x => Int, $y => Int] 这样的东西提供了更接近于结构的东西。更重要的是,$location2 = $location 将在变量 $location2 中创建 $location 的副本,这就是结构的作用。给定 $obj = new MyStruct(),$obj2 = $obj 将 $obj2 设置为与 $obj 相同的对象。
  • 嗯 - 许多 PHP IDE 和框架都会有一定程度的类型强制或检查(而且,由于这个答案是 9 年前写的,PHP 现在能够强制执行类型提示方法参数)——这是关联数组无法做到的。您使用什么实际上取决于所讨论的情况,但是对于大多数人来说,一个类在语法上更接近于一个结构。如果我们开始将 C++ 结构体作为一个比较对象,那么在这一点上实际上是一样的。
【解决方案2】:

你可以使用数组

$something = array(
   'key' => 'value',
   'key2' => 'value2'
);

与标准对象。

$something = new StdClass();

$something->key = 'value';
$something->key2 = 'value2';

【讨论】:

    【解决方案3】:

    我推荐两件事。首先是关联数组

    $person = Array();
    $person['name'] = "Joe";
    $person['age'] = 22;
    

    其次是

    这里有详细的文档:http://php.net/manual/en/language.oop5.php

    【讨论】:

      【解决方案4】:

      这在谷歌上相当高,所以我想我会分享我使用 PHP8 语法实现的伪结构。 toArray() 方法确实依赖 Illuminate\Support\Str 将键转换为蛇形案例(对于 Laravel 模型的质量分配很有用),但是如果它不适合您的用例,只需将其删除。

      基类:

      <?php
      
      namespace App\Infrastructure\Structs;
      
      use App\Infrastructure\Exceptions\CannotMutateStructException;
      use App\Infrastructure\Exceptions\ClassPropertyNotFoundException;
      use Illuminate\Support\Str;
      use ReflectionClass;
      
      abstract class Struct
      {
          /**
           * @param string $name
           * @param mixed $value
           * @throws CannotMutateStructException
           */
          public function __set(string $name, mixed $value): void
          {
              throw new CannotMutateStructException(
                  'Structs are immutable. If you need mutable data then use a class instead.'
              );
          }
      
          public function all(): array
          {
              $reflector = new ReflectionClass(static::class);
              $response = [];
      
              foreach ($reflector->getProperties() as $property) {
                  $response[$property->name] = $this->{$property->name};
              }
      
              return $response;
          }
      
          public function toArray(bool $snakeCase = false): array
          {
              $all = self::all();
      
              if ($snakeCase === false) {
                  return $all;
              }
      
              $snakeCaseAll = [];
      
              foreach ($all as $key => $value) {
                  $snakeCaseAll[Str::snake($key)] =  $value;
              }
      
              return $snakeCaseAll;
          }
      }
      

      使用方法:

      <?php
      
      namespace App\Infrastructure\Structs;
      
      class Person extends Struct
      {
          public function __construct(
              public string $name,
              public int $age,
              public int $heightInCentimetres,
          ) {}
      }
      

      如何与之交互:

      >>> $t = new \App\Infrastructure\Structs\Person('Max', 26, 182);
      
      >>> $t->age
      => 26
      
      >>> $t->age = 40
      App\Infrastructure\Exceptions\CannotMutateStructException with message 'Structs are immutable. If you need mutable data then use a class instead.'
      
      >>> $t->toArray(true)
      => [
           "name" => "Max",
           "age" => 26,
           "height_in_centimetres" => 182,
         ]
      

      希望这对某人有所帮助。

      【讨论】:

        【解决方案5】:

        我今天拼凑了一个“动态”结构类,今晚看了一下,有人写了类似的东西,可以更好地处理构造函数参数,可能值得一看:

        http://code.activestate.com/recipes/577160-php-struct-port/

        此页面上的一个 cmets 提到了 PHP 中的一个有趣的事情 - 显然您可以将数组转换为对象,这使您可以使用箭头表示法来引用数组元素,就像使用 Struct 指针一样C. 评论的例子如下:

        $z = array('foo' => 1, 'bar' => true, 'baz' => array(1,2,3));
        //accessing values as properties
        $y = (object)$z;
        echo $y->foo;
        

        我自己还没有尝试过,但你可能只需要强制转换就可以获得所需的符号 - 如果这就是你所追求的。这些当然是“动态”数据结构,只是用于访问散列中的键/值对的语法糖。

        如果您实际上是在寻找更多静态类型的东西,那么 ASpencer 的答案就是您正在寻找的机器人(正如 Obi-Wan 所说的那样。)

        【讨论】:

          【解决方案6】:

          看来struct数据类型在SOAP中很常用

          var_dump($client->__getTypes());
          
          array(52) {
            [0] =>
            string(43) "struct Bank {\n string Code;\n string Name;\n}"
          }
          

          这不是原生 PHP 数据类型!

          似乎SOAP中引用的struct类型的属性可以作为一个简单的PHPstdClass对象来访问:

          $some_struct = $client->SomeMethod();
          echo 'Name: ' . $some_struct->Name;
          

          【讨论】:

            【解决方案7】:

            只有关联数组是 PHP 中的结构体。

            而且你不能让他们自己严格。

            但是你可以用类和接口来伪造结构严格性,但要注意与结构不同,class instances are not passed in arguments, their identifiers are!


            你可以通过一个接口(或至少接近它)定义一个结构

            结构对对象强制执行某种结构。

            PHP (

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

            任何实现MyStruct 的类都是MyStruct

            它的构建方式不取决于结构,它只是确保返回的数据是正确的。


            设置数据呢?

            设置结构数据是有问题的,因为我们最终会使用 getter 和 setter,它接近于 anemic objectDTO 并且是 considered an anti-pattern by some people

            错误示例:

            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;
            }
            

            然后我们最终得到可能是可变的类实现,并且结构不能改变,这是为了使其成为“数据类型”,就像intstring。 然而,没有办法限制 PHP 中的接口,这意味着人们将能够在一个非结构的类中实现你的结构接口。 确保保留实例immutable

            然后,结构可能会在没有正确数据的情况下被实例化,并在尝试访问数据时触发错误。

            在 PHP 结构类中设置数据的一种简单可靠的方法是通过其构造函数

            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;
               }
            }
            

            使用接口的类型提示:(如果您的 IDE 支持)

            如果您不介意不进行严格的类型检查,那么另一种方法是在 IDE 中使用带有 cmets 的接口或类。

            /**
             * 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
            {
            
            }
            

            使用接口而不是类的原因与最初存在接口的原因相同,因为具有许多实现的许多类可以具有相同的结构,并且使用它的每个方法/函数都将支持具有此功能的每个类界面。

            这取决于您的 IDE,因此您可能需要改用类或不使用它。

            注意: 请记住,您必须在代码的其他地方验证/清理实例中的数据以匹配注释。

            【讨论】:

              【解决方案8】:

              公共类是一种选择,如果您想要更封装的东西,您可以使用抽象/匿名类组合。我最喜欢的部分是自动完成功能仍然适用(对于 PhpStorm),但我没有公共课。

              <?php
              
              final class MyParentClass
              {
                  /**
                   * @return MyStruct[]
                   */
                  public function getData(): array
                  {
                      return array(
                          $this->createMyObject("One", 1.0, new DateTime("now")),
                          $this->createMyObject("Two", 2.0, new DateTime("tommorow"))
                      );
                  }
              
                  private function createMyObject(string $description, float $magnitude, DateTime $timeStamp): MyStruct
                  {
                      return new class(func_get_args()) extends MyStruct {
                          protected function __construct(array $args)
                          {
                              $this->description = $args[0];
                              $this->magnitude = $args[1];
                              $this->timeStamp = $args[2];
                          }
                      };
                  }
              }
              
              abstract class MyStruct
              {
                  public string $description;
                  public float $magnitude;
                  public DateTime $timeStamp;
              }
              

              【讨论】:

                猜你喜欢
                • 2012-07-12
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-08-14
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多