Named constructors

11th January, 2019

Objects are often created using the new keyword before a class name, but sometimes you may want multiple ways to instantiate an object, for example with different parameters, or with an explicitly named method. In some programming languages you can use method overloading to pass different parameters to the constructor but PHP doesn't have that. In PHP we use named constructors like so:

class Distance
{
    private $distance;

    private function __construct($kilometers)
    {
        $this->distance = $kilometers;
    }

    public static function fromKilometers($kilometers)
    {
        return new Distance($kilometers);
    }

    public static function fromMiles($miles)
    {
        return new Distance($miles * 1.60934);
    }
}

Here you'll see that the constructor has been made private so we can't create new Distance objects with our usual new Distance(32). Instead we can call Distance::fromKilometers(32) or Distance::fromMiles(19.88) and we will be returned a new Distance object (as private methods are only accessible within the same class).

An advantage of named constructors is that it allows you to be very explicit as to how you are creating an instance of an object. It may also help with encapsulation and object validation.

Mathias Verraes on Named Constructors in PHP

Tagged: oop php design


Docker and Uncomplicated Firewall (UFW)

11th January, 2019

I ran into an issue yesterday where even though I am using the Uncomplicated Firewall (UFW) with restricted access, I could still connect to some of my internal docker containers from outside my server.

This is because the docker daemon modifies iptables, allowing external connections to your containers if you're not careful!

I have made changes to the relevant docker-compose.yml files, instead of revealing ports on any network I now limit access to the localhost. So instead of

app:
  ports:
   - "8080:80"
  ...

My ports configuration now looks like this

app:
  ports:
   - "127.0.0.1:8080:80"
  ...

This means that my container port 80 will be available on my local network, 127.0.0.1 port 8080.

Remember to restart your docker containers after making this change.

I am then using Nginx as a proxy to manage port forwarding.

More information here:

Tagged: devops docker security


Using PHP 7 (or any other version) from the terminal using Docker

11th January, 2019

Docker logo

Docker has made it possible and easy to run specific software or applications in a precise, repeatable and sharable environment.

For example, lets see how to run our test suite from a specific version of PHP.

Firstly install Homebrew - the missing package manager for OS X.

Then install Docker $ brew install docker (or download from the Docker toolbox)

Once Docker is installed you can run any image from the docker hub. We're interested in the official PHP image.

You can run a container with $ docker run php

But we want to supply some more arguments though:

$ docker run -it --rm -v "$PWD":/app -w /app php:7 php test.php

-i (interactive) keep STDIN open if not attached

-t allocate a pseudo TTY

--rm automatically remove the container when it exits (good for space saving!)

-v "$PWD":/app mount the current working directory (on your host) to the /app directory (on the docker container).

-w /app when the container launches, set the working directory to /app (in the container)

php:7 use the php image, version 7

php test.php the command php will execute the file test.php (providing this exists in your local dir)

So if you are using phpspec and you want to test your specs work in PHP7 you could simply run

$ docker run -it --rm -v "$PWD:/app" -w /app php:7 php vendor/bin/phpspec r

To shorten the quite lengthy command above you could create an alias such as by executing

$ alias php7='docker run -it --rm -v "$PWD:/app" -w /app php:7 php'

or add the above to your ~/.bashrc file.

Then just use it with $ php7 vendor/bin/phpspec r

Tagged: docker php