Last active
September 30, 2017 01:22
-
-
Save Antnee/237334e1eb937892ad7a to your computer and use it in GitHub Desktop.
PHP7 Structs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Ideas for how I'd like to see structs implemented in PHP7 | |
* | |
* In this example, structs are more like lightweight objects that have no | |
* methods, just properties. They can be "instantiated" and all properties will be | |
* null until defined later, as per classes. It is however not possible to set a | |
* value to a property that was not defined in the struct originally. | |
* | |
* Structs can extend other structs, much like classes can. Properties can also | |
* have default values, just as classes can. All properties are public. It is | |
* possible to override previous default property values in the extending struct, | |
* as is done in classes. | |
* | |
* During instantiation, it is possible to set properties in a similar fashion to | |
* defining array keys and values, ie with named arguments. | |
* | |
* Structs are first class. | |
*/ | |
namespace antnee; | |
struct User { | |
string $name; | |
string $email; | |
bool $active; | |
int $maxLogins; | |
} | |
$user = new User; | |
$user->name = 'Antnee'; | |
$user->email = '[email protected]'; | |
$user->active = true; | |
$user->maxLogins = 'yes'; // Throw a catchable fatal error - incorrect type | |
$user->foo = 'bar'; // Throw a catchable fatal error - unknown property | |
/** | |
* Populating a Struct via a _constructor_ looks like a mix of object and array | |
*/ | |
$user = new User( | |
'name' => 'Antnee', | |
'email' => '[email protected]', | |
'active' => true, | |
'maxLogins' => 3, | |
); | |
/** | |
* Function taking a User struct as an argument | |
*/ | |
function acceptUserStruct(User $struct): User { | |
var_dump($struct); | |
return $struct; | |
} | |
acceptUserStruct($user); | |
/** | |
* Extending a struct | |
*/ | |
struct AdminUser extends User { | |
int $maxLogins = -1; | |
bool $admin = true; | |
} | |
$admin = new AdminUser( | |
'name' => 'Antnee', | |
'email' => '[email protected]', | |
'active' => true | |
); | |
echo json_encode($admin); | |
/* Echoes: | |
{ | |
"name": "Antnee", | |
"email": "[email protected]", | |
"active": true, | |
"maxLogins": -1, | |
"admin": true | |
} | |
*/ | |
/** | |
* Pass in _anonymous_ struct as argument | |
*/ | |
$name = 'Me'; | |
$email = '[email protected]'; | |
$active = true; | |
$maxLogins = 5; | |
echo json_encode( | |
struct { | |
'name' => $name, | |
'email' => $email, | |
'active' => $active, | |
'maxLogins' => $maxLogins, | |
} | |
); | |
/* Echoes: | |
{ | |
"name": "Me", | |
"email": "[email protected]", | |
"active": true, | |
"maxLogins": 5 | |
} | |
*/ |
@dshafik and @Rican7 : We've just been looking at the namespacing issue, and we don't feel that it's any worse than the class/interface/trait issue, because:
<?php
class abc{}
interface abc{}
PHP Fatal error: Cannot redeclare class abc in test.php on line 3
<?php
class abc{}
trait abc{}
PHP Fatal error: Cannot redeclare class abc in test.php on line 3
<?php
trait abc{}
class abc{}
PHP Fatal error: Cannot redeclare class abc in test.php on line 3
So you can't have a trait, interface or class in the same namespace with the same name anyway. Not in PHP 5.x anyway. Unsure about PHP 7 (untested), but if it behaves the same then it would be consistent and everyone's happy, yes?
Thanks @gallna for looking into this
love it
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@dshafik - Realised that I'd forgotten to add the anonymous struct that I'd thought of a while back. Added in at #4:
Note that the anonymous struct uses braces. It works much the same as a closure. It could only be type hinted as a struct. Also, the type isn't specified here but is implied from the type of the variables that have been passed in. If you wanted to do strict type checking then you would need to define the struct earlier and instantiate it as in the original example.
Something else that I thought of: In this example that you gave:
I would support this only if
struct
was optional to assist the interpreter in understanding whether I meant the structUser
or the classUser
if this was considered ambiguous, much like if you join two tables in MySQL and there are column names in both tables with the same name. But if this was the case, it would need to have a companion for a class IMO:If you somehow have structs and classes with the same name and the same namespace, and it was allowed, I feel that making this an optional clarifier needs to work both ways