From PHP to Go

I’ve built stuff in PHP for 12 years. For the last 8 weeks I’ve programmed solely in Go. I feel liberated.

Go (or golang if you’re Googling it) is a compiled language, with memory management and some nice concurrency features.

Why not PHP?

My career has been in three phases – firstly working on my own startup (in PHP4!), secondly working predominantly in marketing (in PHP5) and lastly working in startups.

When I started out, PHP made sense. As a self taught programmer, it was incredibly accessible. However that looseness and lack of a “one true way” encouraged me to develop bad patterns. I believe my PHP is now pretty good. I can work around many of the problems people associate with PHP. I accept PHP for the cruft pile it is, but still enjoy working with it.

However, right now PHP does not solve the sort of problems I’m working on. For some time, I have been using the wrong tool for the job. My issue with PHP was around efficiency.

  1. Efficiency of machine utilisation — you can scale out PHP, if you build your app correctly, but you’ll need a tonne of CPU to do it
  2. Efficiency of developer time — with PHP a lot of unit tests are needed to cover off the most basic of things; working round deficiencies in the PHP standard library and lack of typing
  3. Efficiency of running code — creating the entire application context for each request and then destroying it each time is not efficient – it is hard to build a PHP application which has very low and consistent response times (single digit ms)

Why golang?

There is a lot to like about Go. Here’s the things I like.

Lightweight

Go feels like the antidote to heavy-weight do-everything frameworks that are increasingly popular. The standard library feels lean and the language design encourages a similar approach in your own code. Go packages encourage small reusable units of functionality.

Safety

There is nothing like the feeling of refactoring code and then compiling to catch any problems. Lots of bugs that could be introduced when writing PHP are impossible with Go due to type safety.

Easy to learn

Go has one way of doing things. Unsure how to layout code? There is only one way – and go fmt will automatically apply a coding style for you. Go only has one type of loop (the `for` loop). Many things you do in Go, there is only one way of doing it, so learning Go is simply a matter of learning these patterns. For me, having tried to give Scala a crack, I found Go much more approachable.

Productive

It is very easy to be productive with Go – especially when coming from a dynamic language. Automatic memory management (through Garbage Collection) avoids the intricacies of doing it manually. The `:=` short variable declarations make code look dynamic.

Performant

With Go you can quickly write an API that will handle an order of magnitude more requests per second with significantly lower latency than PHP. There is no real tricks involved in achieving this – it is simply out of the box performance.

PHP to golang

Types

PHP has no types. So you can do stuff like:

$a = "A";
$a = 1.1;
$a += "B";
echo $a;

With Go, we’re going to be telling it what type everything is, either explicitly:

var a string
a = "A"

Or implicitly:

a := "A"

The colon-equals operator is incredibly useful and hides a lot of type declaration nonsense. However, `a` is still a string in either case, in Go we can’t just then do this:

a += 1.1

Occasionally you’ll need to move data between types.

  • strings to numbers `a, err := strconv.ParseInt(”12345″)`
  • numbers to strings `b := fmt.Sprintf(”%v”, a)`
  • direct casting `a := []byte(”foo”)` or if `i` is an `int` `j := int64(i)`

Objects

Hold onto your hats folks – Go is not an object oriented language. Since 2008 when a man named Neil explained object oriented design, and I invested an enormous amount of time reading the classic texts, I have been wedded to OOP. I could not understand why
Java land was such a problem.

With Go, you can attach methods to a type. So you can have some of the features of OOP. But remember – this is Go – we’re focussed on being lean. So with Go you’ll often see structs with public properties.

type User struct {
    GivenName, FamilyName string
    Age int
}

func main() {
    u := &User{"Dave", "Gardner", 34}
    fmt.Println(u)
}

http://play.golang.org/p/61B3jZSCn9

Job done, thank you kindly.

  • There are no `public`, `private`, `protected` keywords – instead, if the first character of a property is uppercase, it is “exported” from the package (think public) otherwise it is private.
  • Go has no inheritance for structs, so `protected` is meaningless.
  • The go way is simply to make stuff public, unless you have a reason not to. For entities, just have them public.
  • The `&` operator is saying “make an instance of this struct and return a pointer to it”
  • You should construct structs explicitly naming the fields (the method I used above is not recommended practice and may at some point be deprecated), eg: `&User{GivenName:”Dave”, FamilyName:”Gardner”, Age: 34}`

If we want to, we can attach a method to this data type.

func (u *User) Name() string {
    return fmt.Sprintf("%s %s", u.GivenName, u.FamilyName)
}

http://play.golang.org/p/_0vevLo9CJ

We could just as easily declare a string type and attach a method.

type Name string

func (f Name) SayHello() string {
    return fmt.Sprintf("Hello %s!", f)
}

http://play.golang.org/p/e2msqvYAGL

Packages

One interesting point here is the “exported” concept — when writing Go you’re thinking about what stuff you will be exporting from your package, both in terms of struct properties, functions, methods, types, constants etc. Within a package, there is no facility for information hiding — any piece of code can access the properties (exported or otherwise) of any variables.

This has lead me to construct my programs as small, often reusable, packages. A package is where you carry out your information hiding.

A word on scope

Unlike PHP’s namespaces, Go’s packages define scope. If I were to write this:

package foo

var bar string

Then `bar` is in the global scope within this package, but is entirely unaccessible outside of the package. If I had written `Bar` then it would have been exported and directly accessible outside the package.

PHP has global scope, object scope (for properties) and local function scope (for locally declared variables). PHP also has some strange syntax for dealing with scope.

<?php

$bar = "The Three Greyhounds";

function foo() {
    global $bar;
    echo "$bar\n";
}

In Go we would write:

var bar string = "The Three Greyhounds"

func foo() {
     fmt.Println(bar)
}

http://play.golang.org/p/7yOmIlW6nv

Here we are enclosing around the scope of `bar` from the function `foo`.

Go also has more levels of scope, for example within an `if` statement.

<?php

if ($a > 0) {
    $b = 1;
} else {
    $b = 0;
}

echo $b;

In Go you might be tempted to write:

func main() {
    if a > 0 {
        b := 1
    } else {
        b := 0
    }

    log.Println(b)
}

http://play.golang.org/p/2c5yLLLbCt

However `b` was created from within the scope of the `if` statement only and so is not defined when you come to `Println`.

Interfaces and duck typing

In PHP you would write `class foo implements bar` – explicitly declaring that your class foo is going to implement bar. In Go, if something implements the methods defined in an interface, then it automatically implements that interface. Let’s have a look.

type Stringer interface {
    String() string
}

So to be a `Stringer`, we just need to have a method named `String` that returns a `string`.

func (u *User) String() string {
    return fmt.Sprintf("%s %s (%v)", u.GivenName, u.FamilyName, u.Age)
}

Errors and Exceptions

Hold onto your hats again folks – Go does not have Exceptions. Instead, the Go way is to return an error (something that implements the Error interface) from a function or method and then check this explicitly. Let’s have a look:

foo, err := gossie.NewConnectionPool()

// now it's up to me!

The other thing we’re introducing here is Go’s concept of multiple return values — we can return a connection pool and an error. This same pattern is used in much Go code; make call, check and handle returned error.

if err := DoFoo(); err != nil {
    // handle error
}

There is also `panic` and `recover`. These are for exceptional circumstances – where there is some critical run-time bug. An example is if you attempt to do something with a `nil` struct:

func main() {
    var user *User
    fmt.Println(user.Name())
}

http://play.golang.org/p/ven1GGzvyl

It is possible to recover from panics. A good pattern here would be to catch any panics within an HTTP request handler, so that you can serve up an HTTP 500 Internal Server Error (instead of the program dying). However I rarely use this method of recovery — panic/recover is not designed for normal error handling flow.

PHP Arrays

Arrays are one of the most obviously different areas to PHP – stemming from the fact that PHP has a single construct that does all the things. With Go, we’ll need to declare explicitly when we want a map vs a list etc. In PHP, everything is an array. In Go, you’ll find yourself learning more about data structures and then picking the right one for the right workload (Trie anyone?).

Array

Literal arrays in PHP:

$arr = array("dave", "loves", "cheese");

And in Go:

arr := [3]string{"dave", "loves", "cheese"}

In Go world, no one ever uses arrays directly (nearly). Instead you can use a `slice` which you can do by simply omitting the number of elements in the declaration.

arr := []string{"daves", "loves", "cheese"}

Here `arr` is a `slice` of strings. Remember that Go is typed — you have to tell it what’s in your array, and then the type system will make sure you stick to that.

Once we have a slice, we can append easily enough:

$arr[] = "dreams"
arr = append(arr, "dreams")

Maps

Literal maps in PHP:

$map = array("foo" => "bar", "baz" => "bing");

And in Go:

m := map[string]string{"foo":"bar", "baz":"bing"}

Test if something exists in a map in PHP:

$exists = array_key_exists($map, "baz");

And in Go:

_, exists := m["baz"]

http://play.golang.org/p/pwOwd3AM_1
The underscore is a placeholder for the element – by using an underscore we’re explicitly saying we don’t care what this return value is.

Other useful data structures

Conclusions

Learning new languages is important for any developer. For me, it was always something I knew I needed to do, but something I could never prioritise. I also found a real barrier being back at the start – not being an expert anymore. I feel like Go changed that. It was understandable. It was accessible. It showed me a new way of solving problems. With this knowledge I could, if I wished, take some of these patterns back to PHP land – but I probably won’t. Once you’ve been using Go, it would seem perverse to switch back to PHP.

In my next post I’ll introduce some patterns I use when programming in Go.

Tags: , ,

4 Responses to “From PHP to Go”

  1. theUniC says:

    Liked the insights about Go that you are providing with your post. Don’t like some assertion about PHP, that at least for me it is simply not true. Also, I think that your post would be a more valuable resource if you could just explain some of the situations you have faced and where PHP didn’t fit. My sense about it, is that PHP and Go are totally different with different characteristics and with different design decisions in mind, and compare them is like compare pears with apples.

  2. Big fan of both pears and apples. Good article; coming from a PHP background I found it useful especially the explanation of scope which I’m sure would have tripped me up.

    For me it would have also been useful to expand on Go interfaces as I think the example above it a little brief and I think there is one small error, when defining an interface I think it should be:
    type Stringer interface {…

  3. Dave says:

    Fixed! Cheers.

  4. Elgs says:

    I used to have most of my work on Java. Now I’m migrating my work from Java to Go and Nodejs. I have been struggling to make the decision Go or Node. To me, they are equally performant. They both have great web framework, Martini for Go and Express for Node. Npm seems to be better than go get. Go has native binary while Nodejs does not. To me writing code in javascript is a lot more enjoyable than in Go. They seems to be both excellent choices. I’m still struggling.

Leave a Reply