PHP 有结构数据类型吗?

PHP 中是否有类似 struct 数据类型的东西? 有人能给我举个 struct 数据类型的例子来更好地理解这一点吗?

如果没有这样的数据类型,那么如何获得行为类似于 struct 的数据类型?

133012 次浏览

可以使用数组

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

与标准对象。

$something = new StdClass();


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

我推荐两样东西,第一是 关联数组

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

第二个是 课程

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

与 struct 最接近的是一个所有成员都为 public 的对象。

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


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

我觉得看看 PHP 类文档就值了。 如果您需要一个一次性的结构,使用 Alex 答案中提到的 StdObject

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

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

这个页面上的一条评论提到了 PHP 中的一件有趣的事情——显然你可以将数组转换为对象,这样你就可以使用箭头符号来引用数组元素,就像 C 语言中的结构指针一样。该评论的例子如下:

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

我自己还没有尝试过这种方法,但是也许你可以通过铸造来得到你想要的符号——如果这就是你想要的。这些当然是“动态”数据结构,只是用来访问散列中的键/值对的语法糖。

如果您实际上正在寻找更加静态的类型,那么 ASpencer 的答案是您正在寻找的机器人(正如欧比-万可能会说的那样)

看起来 struct的数据类型是 通常在 SOAP 中使用:

var_dump($client->__getTypes());


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

这不是原生 PHP 数据类型!

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

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

在 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

它的构建方式与结构无关,它只是确保返回的数据是正确的。


设置数据怎么样?

设置 struct 数据是有问题的,因为我们最终得到的是 getter 和 setter,它接近于 贫血的物体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;
}

然后我们最终得到的类实现可能是可变的,并且一个 struct 不能变异,这是为了使它成为一个“数据类型”,就像 intstring一样。 然而,PHP 中的接口无法限制这一点,这意味着人们将能够在一个不是 struct 的类中实现结构化接口。 确保实例 < a href = “ https://stackoverflow. com/questions/14427050/immutable-Objects-in-php”> 保持不变

此外,当尝试访问数据时,可以在没有正确数据和触发器错误的情况下实例化 struct。

在 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 中使用带注释的接口或类。

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

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

公共类是一种选择,如果您想要更封装的东西,您可以使用抽象/匿名类组合。我最喜欢的部分是,自动补全仍然工程(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;
}

这在 Google 上是相当高级的,所以我想我应该分享一个使用 PHP8语法的伪结构的实现。ToArray ()方法确实依赖于 Illumination Support Str 将键转换为 Snake case (对于针对 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,
]

希望这能帮到别人。

编辑: 在 PHP8.1中,我们现在有了 只读属性,它可以使这个过程更加简洁。

编辑: 通过 PHP8.2,我们现在有了一个简洁的 甚至更多来实现这一点。作为一个很好的例子,我强烈推荐阅读本文的全文: https://stitcher.io/blog/evolution-of-a-php-object

然而,一般的 jist 是编写 readonly class Foo {},它删除需要添加它对每个属性。