在php中构造数据类型?


72

谁能给我示例php中的structs数据类型?为什么突然间在php中有类似struct的东西?


13
您在哪里阅读此信息?PHP从来没有实际的struct数据类型。
BoltClock

请显示代码或指向您在PHP中了解结构的链接。
Alex

5
当他var_dump-soap对象时,他可能会看到struct一词。
米洛·拉玛

@ktm,您将此称为结构吗?
Pavel V.

1
@ktm不幸的是,PHP不支持C / C ++中的结构。因此,您无法执行以下操作:class pseudostruct { (int) myint; (char) mychar; (string) mychar; } myObj = new pseudostruct;。如果PHP具有此功能,那就太好了,因为我们可以声明数据结构并希望以非常简单和有效的方式读取数据并为它们赋值,就像在C语言中一样。如果我们可以预定义精确的内存,那也很好。变量的大小或使用malloc。然后将数据读取到我的伪结构类的变量会很有趣!
约翰·波

Answers:


105

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

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

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

我想看看PHP类文档是值得的。如果需要一次性结构,请使用alex's answer中提到的StdObject


4
那将与之class MyStruct相反object MyStruct;)
BoltClock

1
在这里“打招呼”是适当的回应吗?在午休时间教我快速解答...
ASpencer 2010年

1
@ASpencer也感谢您提及alex的答案。
永远

用类代替struct是一个糟糕的选择。一个结构仅连接两个数据元素。类有额外的开销。例如,给定Int是一个4字节的内存区域,结构位置{x:Int,y:Int}是8个字节。使用$ x = 0,$ y = 1,$ location = [$ x => Int,$ y => Int]之类的东西可以更接近struct。更重要的是,$ location2 = $ location将在变量$ location2中创建$ location的副本,这是结构将执行的操作。给定$ obj = new MyStruct(),$ obj2 = $ obj将$ obj2设置为与$ obj相同的对象。
经常混淆

1
好吧-许多PHP IDE和框架都将在某种程度上进行类型强制或检查(并且由于此答案是9年前编写的,因此PHP现在能够对方法参数强制进行类型提示)-这是您需要做的事情不能与关联数组。您实际使用的内容取决于所讨论的情况,但是对于大多数人来说,类在语法上更接近于结构。而且,如果我们开始将C ++结构作为比较,那一点实际上是相同的。
ASpencer

49

您可以使用数组

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

带有标准物体。

$something = new StdClass();

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


2

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

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

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

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

我还没有尝试过这种方法,但是可能只是通过投射即可获得所需的符号-如果仅此而已。这些当然是“动态”数据结构,只是用于访问哈希中键/值对的语法糖。

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


2

似乎该struct数据类型通常在SOAP中使用

var_dump($client->__getTypes());

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

这不是本机PHP数据类型!

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

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

1

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

而且您不能对它们进行严格限制。

但是您可以使用类和接口对结构进行严格的伪造,但是要注意,与结构不同,类实例不会在参数中传递,它们的标识符是


您可以通过接口(或至少靠近接口)定义结构

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

PHP(<= 7.3)没有本机结构,但是您可以使用接口和类型提示来解决它:

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

任何实现的类MyStruct都是MyStruct

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


设置数据呢?

设置结构数据是有问题的,因为我们最终会遇到吸气剂和设置器,并且它很接近贫血对象DTO,并且被某些人认为是反模式

错误的例子:

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

然后,我们最终得到了可能是可变的类实现,并且一个结构不得突变,这是使其成为“数据类型”,就像int,一样string。但是,没有办法用PHP中的接口来限制它,这意味着人们将能够在不是结构的类中实现结构接口。确保实例保持不变

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

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

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。

/**
 * 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,因此您可能需要改用类,或者只使用类而不使用它。

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


0

公共类是一个选择,如果您想封装更多内容,可以使用抽象/匿名类组合。我最喜欢的部分是自动完成仍然可以(对于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;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.