DEV Community

Cover image for Introduction to Go for PHP Developers
Andrew Davis
Andrew Davis

Posted on

Introduction to Go for PHP Developers

Recently, I started working on an internal CLI app for my team at work. My main programming language of choice is PHP, but I wanted to create this program in a language that could run on any platform without having to have an interpreter already installed. I also wanted the app to be self contained in a single binary for easy distribution and installation. I downloaded Go and was pleasantly surprised at how easy to learn the language is and how productive I got with it in a short amount of time. Go’s procedural programming model really clicked with my PHP brain and I was able to get this app up and running quickly. There are some notable differences with PHP though, so I want to share them for any other PHP developer who wants to learn Go in the future.

Installation

MacOS

I use a Mac so I installed Go using Homebrew: brew install go. If you don’t have Homebrew on your Mac, I highly recommend using it.

Windows & Linux

The Go website has downloads for each OS, including a walk-through installer for Windows that makes the installation easy.

Getting Started

In Go, all source code for each Go project is stored under a single directory called the GOPATH. By default, the GOPATH is set to go in your home folder, e.g. /Users/andrewdavis/go. In the GOPATH, there is a bin directory and a src directory. The bin directory holds any binaries you download as dependencies. You will want to add the bin folder to your PATH environment variable. You can do so in your terminal’s .bashrc/.zshrc file with export PATH=$PATH:$(go env GOPATH)/bin. To start learning Go, you can download the Tour of Go program by running the following in your terminal go get golang.org/x/tour/gotour. go get downloads the source code and binary for a third party dependency using the provided path. Now, you can run gotour in your terminal and it will start a web server and point your browser to it.

To create a project, make a directory under src in your GOPATH: mkdir -p $GOPATH/src/helloworld. Open that folder cd $GOPATH/src/helloworld and create a file called main, touch main.go. In that file, put the following:

package main

import "fmt"

func main() {
  fmt.Println("Hello world!")
}
Enter fullscreen mode Exit fullscreen mode

The starting point for all Go programs is the main function in the main package. Next, you can run go run main.go to run the program. You can also run go install and the program will be compiled and put in the bin directory so you can execute helloworld in your terminal and it will run your code.

Major Differences from PHP

Now that you have a project set up, you can start exploring the different Go features. One of the first things you will notice is that semi-colons are not required in Go. The end of a statement is detected by a new line. Here are some more differences that took me some time to understand:

Variables

Go is a statically and strongly typed language so every variable has a type assigned to it. Variables in functions are assigned using the := operator and this operator will automatically set the variable type for you: name := "Andrew" // name is now a string. To create a variable without setting any data in it or to create one outside of a function you have to use the var keyword: var name string.

If statements

If statements work the same as they do in PHP, however they don’t have to use parentheses around the boolean check. The difference confused me at first when reading Go code. However, I think it makes the code a little easier to read.

package main

import "fmt"

func main() {
  value := false
  if value {
    fmt.Println("Value is true")
  } else {
    fmt.Println("Value is false")
  }
}
Enter fullscreen mode Exit fullscreen mode

Packages vs Namespaces

Go uses the term package to namespace it’s content. If you have a folder called controllers in your Go code, each file in that folder would start with package controllers. To import controllers from another package, you would write import “helloworld/controllers”. Anything in your package that has a name that starts with a capital letter can be used in another package. If you have a function named, func HelloWorld() in controllers, you would then be able to call controllers.HelloWorld() to run the function once controllers is imported. Anything that does not start with a capital letter can only be used from the same package. No need for private or public!

Strings

In Go, all strings must be surrounded by double quotes. A single quoted value in Go is for a rune (a single Unicode code point). By habit, I type my strings with single quotes since that is common practice in PHP. It takes a little time to adjust to always using double quotes.

var name = "Andrew"
var copy = '©'
Enter fullscreen mode Exit fullscreen mode

Structs vs Classes

Go does not have a class system like PHP. Instead, it uses structs to model custom data structures. You can write a struct like this:

package main

type Cup struct {
  name string
  color string
  volume int
}
Enter fullscreen mode Exit fullscreen mode

You can add methods to a struct by creating a function that references a struct in parentheses before the function name.

func (c Cup) nameAndColor() string {
  return c.name + ": " + c.color
}
Enter fullscreen mode Exit fullscreen mode

You can then create an instance of a struct by writing the struct name and passing in its initial values in curly braces. Method execution uses dot notation.

func main() {
  c := Cup{name: "Solo", color: "Red", volume: 12}
  c.nameAndColor() // returns "Solo: Red"
}
Enter fullscreen mode Exit fullscreen mode

To create a method that modifies the struct instance, the method must reference a pointer to the struct:

func (c *Cup) crush() {
  c.volume = 0
}
Enter fullscreen mode Exit fullscreen mode

Errors

In Go, errors are not treated like exceptions. There is no throw or catch mechanism. Instead, errors are returned from functions if one has occurred. Go supports returning multiple values from a function. If you call a function that could return an error, you have to check if the error is not nil to handle the error condition.

package main

import "fmt"

func GetName(name string) (string, error) {
  if name == "Bob" {
    return "", fmt.Errorf("Name cannot be Bob")
  }

  return name, nil
}

func main() {
  name, err := GetName("Bob")
  if err != nil {
    fmt.Println("Uh-oh an error has occurred")
  }
}
Enter fullscreen mode Exit fullscreen mode

Fin

Of course, there is a lot more to learn about Go, but hopefully this will help you get started. There are a lot of great resources for studying Go. The most helpful for me were the Go docs and Go By Example. If you have any thoughts or questions, please leave a comment. Thanks for reading!

The PHP logo comes from the PHP website.
The Go gopher image comes from @egonelbre.

Top comments (16)

Collapse
 
dopitz profile image
Daniel O. • Edited

In Go, errors are not treated like exceptions. There is no throw or catch mechanism. Instead, errors are returned from functions if one has occurred.

This is a "no go" for me.

Collapse
 
ameliagapin profile image
Amelia Gapin

At first, I wasn't a fan of this. It made the code feel cumbersome. After a bit, I not only got used to it, but came to embrace it. It makes error handling much more a natural part of the way you code. You can avoid the scoping of a try/catch block because you don't have to put your code into another block.

The compiler will ensure that you've recognized the error is part of the return (when using a multi-return function) so you don't have to worry about being unaware of it. If you do anything with it and what you do is up to you. You could choose to ignore it by assigning it to _ instead of a variable.

Collapse
 
restoreddev profile image
Andrew Davis

It’s not as bad as you might think. It forces you to account for each error which makes your code a little more resilient.

Collapse
 
david_j_eddy profile image
David J Eddy

I read that same line and instantly thought `oh, crap. error catching is going to be a mess'. But then I thought about it; most error catching I do should be handled in a much more graceful way. Not a 'here is an error, return stack trace'. After reading this article I feel like going Go a try, again.

Collapse
 
okolbay profile image
andrew • Edited

4 steps to love it:
1 try to implement clean project structure
2 use exceptions to propagate errors
3 realize that exception is part of interface, and to avoid coupling, or catching SQL exceptions in HTTP controller you need exception per layer
4 give up and embrace go’s way of handling errors

not to mention that throw is essentialy a GOTO instruction, its slow and ask yourself - how many times, when catching “business-logic” related exception from your code you were interested in stacktrace?

Collapse
 
igormp profile image
Igor Moura

I honestly love it. As a hardcore C user, it feels pretty natural to me and makes you deal with the error as soon as possible instead of ignoring it.

Collapse
 
presto412 profile image
Priyansh Jain

Can second this

Collapse
 
brpaz profile image
Bruno Paz

Great article.

I have been working in both PHP and Go on the last months in my company, and I think they really complement each other very well. Some of the known weak points of PHP like concurrency or long running processes are the strengths of Go.

Plus, Go is really great for applications like system tools, command line tools or small services (ex: slack bots, webhooks listeners, etc), because since it compiles into a single binary makes it incredibility easy to install and run in any system.

PHP is still one of my favorite languages for general web application development as I can write clean code really fast, thanks to OOP design and frameworks like Symfony.

Adding a mix of Go for more specific use cases and you can build almost anything.

So,if you are a PHP developer, I really recommend taking the time to learn Go.

Collapse
 
fzammit profile image
Fabio Zammit

Great insights.

I am curious to see whether you had an instance where GO would consume the data received by the Symfony APP i.e. listening to some form of events etc? If so could you please give some examples as to how you went about this.

Thanks :)

Collapse
 
ladydascalie profile image
Benjamin Cable • Edited
func (c Cup) nameAndColor() string {
  return c.name + ": " + c.color
}

This would be much better served by satisfying the Stringer interface:

func (c Cup) String() string {
     return c.name + ": " + c.color
}

I would recommend following the tour here: tour.golang.org/methods/17
To see in greater detail why this is a more useful way to do this.

Collapse
 
restoreddev profile image
Andrew Davis

Thanks for pointing that out. I just wrote the method as an example, nothing more.

Collapse
 
jay97 profile image
Jamal Al

hey, you said Go is a"program in a language that could run on any platform without having to have an interpreter already installed". Could you explain how that works, so you can write Go App and run it on other machines without having to install some kind of interpreter?

Collapse
 
blackcat_dev profile image
Sasha Blagojevic

I was just thinking about picking up Go, when your post popped up on Facebook, as if they were reading my mind...or search history...God damn you Zuck, you lizard!

Collapse
 
restoreddev profile image
Andrew Davis

It's definitely worth checking out. I like it because it stretches my brain in ways that PHP and JavaScript do not.

Collapse
 
maxdevjs profile image
maxdevjs

golang.org/x/tour/gotour has moved to golang.org/x/tour

Collapse
 
inambe profile image
Inam Ul Haq

GO seems combining features of several languages. Package system from Java, Structs from C, Pointers from C. Indentation from python. Seems powerful.