If I have a function that receives eg a Message, it means an instance of the class right? So somehow my assoc.array/object still needs to be instanced, and if I do just $message = new Message($theData) … it doesn’t auto assign properties right? That would be handy though still very much boilerplate.
I guessthe language is just designed for how it’s been used so far, may e it will change if JIT makes php more open ended in its uses.
Anyway I was curious so I wanted to try this out with the trait method here is working code that illustrates this.
<?php
/* trait to cast from any iterable to class */
/* reusable - close to what I think you are asking for */
trait castFrom
{
static function castFrom($data)
{
if (!is_iterable($data) and !is_array($data) and !is_object($data)) return null;
$class = new self();
foreach((array)$data as $key => $value)
{
if (!property_exists($class, $key)) continue;
$class->$key = $value;
}
return $class;
}
}
class Foo
{
use castFrom; // use the castFrom trait
public string $str = 'blah';
public int $num = 5;
public function hello() { echo "{$this->str} : {$this->num}\n"; }
}
class Bar
{
use castFrom; // we can use the castFrom trait again and again
public int $x = 0;
public int $y = 0;
public function hello() { echo ($this->x * $this->y) . "\n"; }
}
$data = ['str' => 'foo', 'num' => 7, 'x' => 3, 'y' => 7];
$foo = Foo::castFrom($data);
$foo->hello();
print_r($foo);
$obj = (object)$data;
$bar = Bar::castFrom($obj);
$bar->hello();
print_r($bar);
/* you could just use create functions form the class */
class Creator
{
static public function createFromArray($data) {} // create from array
static public function createFromObject($data) {} // create from object
static public function createFromSerial($data) {} // etc..
static public function createFromJson($data) {}
}
EDIT: Added ugly check to make sure the type can be iterated over. class Foo {
public function __construct(string $name, array $options)
{
$this->name = $name;
if ($options->enableFlag) { ...
I want to declare what $options are, in TS I could do:type TFooOptions = { enableFlag: boolean; userIds: number[]; }
Then
function __construct(string $name, TFooOptions $options) ...
Otherwise how do I get proper typechecking if the IDE doesn't know what $options are?is that creating a JS class under the hood or is just a hint for the compiler?
What I do , but I don't work with recent PHP versions is to create this as a class, then to make this easy to construct objects from JSON i add a static function fromObject or fromJson that does it for me. Using real classes could prevent bugs when working with shit APIs like Microsoft TTS , where they have 2 endponts and one returns objects like voice: {name:"Bob"} and the other voice: {Name:"Bob"} so my code will wrap both type of responses into a well defined class.
I don't think there is a PHPDoc annotation just to hint what that object looks like but I will be happey to be shown a way.
class TFooOptions
{
public function __construct(
public bool $enableFlag,
public array $userIds = [],
) {
}
}
$options = new TFooOptions(
enableflags: true,
userIds: [1,2,3]
);
new Foo('Bob', $options);
Or if just for IDE checking, you could use the @property docblock value on the class.[1]: https://psalm.dev/ [2]: https://psalm.dev/docs/annotating_code/type_syntax/array_typ...