For advanced PHP developers, stepping into Go is often more attractive than Node.JS. But the Go library seems to be missing so much useful stuff found in the PHP library. How can one switch faster ?
Migrating away from PHP
Converting one’s development practice from PHP to Go is not an obvious rewrite with “just” a new syntax : more often than not, it will imply completely rethinking the organization of one’s programs, when realizing that many things held as obvious were really a consequence of the former language runtime types and organization optimized for minimal parsing (think autoloading with PSR-4, or the myriad of different tasks served by PHP so-called arrays). When porting code to Go, all of these PHP underpinnings upon which code depends need to be replaced, making the first conversions harder to deliver.
This is where PHP2Go comes in.
The PHP2Go library
To ease these first migrations and allow one to deliver code fast even when just
starting, the github.com/syyongx/php2go
has been available since Go 1.10, and
offers over 140 functions designed as Go equivalents for the PHP functions by
the same name.
It even includes a Ternary
function to convert PHP ?:
ternary expressions,
which Go chose to exclude.
Here is how it is used, starting with the replaced PHP code:
|
|
As the Go conversion below shows, all it takes is importing — possibly using a dot import — the package, and use the PHP2Go functions instead of the original. Because exported identifiers in Go need to start by an uppercase letter, the conversion implies uppercasing the first letter of PHP functions.
|
|
Limitations
Because the languages differ so much, some limitations need to be accounted for, as this example shows :
- The function signatures may differ: in this fragment
Getcwd()
honors the specifics of its underlying Go implementationos.Getwd()
, returning an error value along with the result, instead of keeping the exact PHP signature, to stay closer to the Go style error handling. Don’t just ignore them as is done in this tiny demo. - Because PHP runtime functions are typically loosely types, their Go counterparts
rely on
interface{}
values to simulate the dynamic typing available in PHP. This causes the result of some functions likeTernary
not to be immediately usable in some cases, requiring av.(<type>)
type assertion as in the example ; or aswitch v.(type)
type switch when the result type is not known in advance.
As the example show, the resulting code is more verbose and not idiomatic, and as such will look alien to most Go developers. To complete the comparison, here is a native Go version for the same tiny example: it is not really less simple, and any gopher will be familiar with it.
|
|
Practical use
Some functions are significantly more useful, especially those operating the myriad operations on PHP arrays, which have not direct equivalent in Go, and will often be the most complex part of any conversion from PHP to Go.
The php2go
package includes many of these, taking []interface{}
arguments:
PHP 7.4 | php2go v0.9.4 |
---|---|
array_change_case | |
array_chunk | ArrayChunk |
array_column | ArrayColumn |
array_combine | ArrayCombine |
array_count_values | ArrayFill |
array_diff_assoc | |
array_diff_key | |
array_diff_uassoc | |
array_diff_ukey | |
array_diff | |
array_fill_keys | |
array_fill | |
array_filter | |
array_flip | ArrayFlip |
array_intersect_assoc | |
array_intersect_key | |
array_intersect_uassoc | |
array_intersect_ukey | |
array_intersect | |
array_key_exists | ArrayKeyExists |
array_key_first | |
array_key_last | |
array_keys | ArrayKeys |
array_map | |
array_merge_recursive | |
array_merge | ArrayMerge |
array_multisort | |
array_pad | ArrayPad |
array_pop | ArrayPop |
array_product | |
array_push | ArrayPush |
array_rand | ArrayRand |
array_reduce | |
array_replace_recursive | |
array_replace | |
array_reverse | ArrayReverse |
array_search | |
array_shift | ArrayShift |
array_slice | ArraySlice |
array_splice | |
array_sum | ArrayUnshift |
array_udiff_assoc | |
array_udiff_uassoc | |
array_udiff | |
array_uintersect_assoc | |
array_uintersect_uassoc | |
array_uintersect | |
array_unique | |
array_unshift | |
array_values | ArrayValues |
array_walk_recursive | |
array_walk |
Conclusion
The php2go
module is a useful tool allowing experimented PHP developers who are
just beginning Go to deliver their first projects in record time, making the switch
from one technology to the other easier on management.
For most needs, though, it shows how difficult moving from one language to another without changing work habits can be:
- PHP is designed on top of dynamic typing and its “anything goes” arrays, which provide both arrays, maps, queues, and stacks, and preserve the insertion order when used as maps, whereas nothing equivalent exists in the Go runtime.
- Go is statically typed, so converting a PHP project to Go will most often mean
entirely rethinking the data model instead of attempting to shortcut the needed
redesign by using a porting library like
php2go
.
In the end, someday, the technical debt needs to be repaid, so better do it as soon as possible.