Twenty hands-on lessons that translate what you already know from Go into PHP. Each lesson shows a familiar Go idiom, gives you a small problem to solve in PHP, and checks your answer by running it on Wandbox (internet connection required). Your progress is saved locally, and a reference solution is one click away if you get stuck.

    Go ⇄ PHP cheat sheet

    A comprehensive quick reference pulled together from all 20 lessons — every idiom mapped between the two languages, in one place.

    1. Variables & Types

    ConceptGoPHP
    Declare + assignx := 1$x = 1; (assignment is declaration)
    Change type latercompile errorallowed — variables are dynamic
    Numbersint, int64, float64, …int and float
    Typed signaturefunc f(x int) stringfunction f(int $x): string
    Formattingfmt.Sprintf("%s is %d", n, a)"$n is $a" in double quotes
    Failurereturn val, errthrow new Exception(...) (lesson 16)
    NamingcamelCasesnake_case functions

    2. Strings & Interpolation

    ConceptGoPHP
    Format into a stringfmt.Sprintf("%s is %d", n, a)"$n is $a" or "{$n} is {$a}"
    Concatenatea + b$a . $b
    Uppercasestrings.ToUpper(s)strtoupper($s)
    Substring teststrings.Contains(h, n)str_contains($h, $n)
    Lengthlen(s)strlen($s)
    Joinstrings.Join(parts, ", ")implode(", ", $parts)
    Splitstrings.Split(s, ",")explode(",", $s)

    3. Arrays as Lists

    ConceptGoPHP
    Literal[]int{1, 2, 3}[1, 2, 3]
    Appends = append(s, x)$s[] = $x;
    Lengthlen(s)count($s)
    Membershipslices.Contains(s, x)in_array($x, $s, true)
    Sumfor range looparray_sum($s)
    Indexs[0]$s[0]
    Semanticsslice header, shared backing arrayvalue: copies on assign/pass (copy-on-write)

    4. Associative Arrays

    ConceptGoPHP
    Literalmap[string]int{"a": 1}['a' => 1]
    Read with defaultv, ok := m[k] + if$m[$k] ?? $default
    Key exists?_, ok := m[k]array_key_exists($k, $m)
    Setm[k] = v$m[$k] = $v;
    Deletedelete(m, k)unset($m[$k]);
    Iteratefor k, v := range mforeach ($m as $k => $v)
    Iteration orderrandomized on purposeinsertion order, guaranteed
    All keys / valuesmanual looparray_keys($m) / array_values($m)

    5. Functions

    ConceptGoPHP
    Signaturefunc f(x int) stringfunction f(int $x): string
    Default value— (write a wrapper)string $g = "Hello"
    Optional / nullable*string + nil check?string $x = null
    Either-or typeany + type switchint|string + is_int()
    Readable call sitesfunctional-options patternf(name: "Ada")
    No return valueomit the type: void
    Multiple returns(int, error)return an array, or throw (Lesson 16)

    6. Null, ?? & ?->

    ConceptGoPHP
    The absent valuenil (behavior varies by kind) + zero valuesnull, one value for everything
    Nilable type*Address?Address
    Map lookup with defaultv, ok := m[k] + if$m[$k] ?? $def
    Deep accessnil check per hop, or panic$u?->address?->city — null anywhere → null
    Null checku == nil$u === null; isset($x) = declared and not null
    Assign-if-absentif _, ok := m[k]; !ok { m[k] = d }$m[$k] ??= $d;

    7. Comparisons & Type Juggling

    ConceptGoPHP
    Equality== (compile-time type-checked)=== — use it always; == juggles
    Inequality!=!==
    Mixed-type comparewon't compile"1" == 1 is true; "1" === 1 is false
    Condition typemust be boolanything — coerced via truthiness
    Falsy valuesonly falsefalse, 0, 0.0, "", "0", [], null
    Three-way comparecmp.Compare(a, b)$a <=> $b

    8. Control Flow & match

    ConceptGoPHP
    ifif x > 0 { }if ($x > 0) { } — parens required
    Value switchswitch day { case ...: }match ($day) { ... => ... } (skip legacy switch)
    Condition chainswitch { case a > b: }match (true) { $a > $b => ... }
    Grouped casescase "sat", "sun":"sat", "sun" =>
    Comparisonstrict (typed)match: strict ===; switch: loose ==
    Statement or expression?statementmatch is an expression — assign it, return it
    Unhandled valueruns nothingthrows UnhandledMatchError

    9. Classes & Objects

    ConceptGoPHP
    Define a typetype T struct {...} + external methodsclass T { ... } — everything inside
    ConstructNewT(...) (convention)new T(...)__construct (language feature)
    Fields + constructorstruct block + assignment in NewTpromoted: __construct(private int $x = 0)
    Receiverfunc (a *T) M() — named, explicit$this, implicit in signature, mandatory in body
    Member accessa.field (auto-deref)$a->field (also auto-deref)
    VisibilityExported / unexported casepublic / private / protected
    Copy semanticsvalue receivers copy; pointers don'tobjects are handles — never copied on assignment or call

    10. Interfaces, Inheritance & Abstracts

    ConceptGoPHP
    Interfaceimplicit satisfactioninterface Shape {} + explicit implements Shape
    Inheritancenone — embed insteadextends (single parent only)
    Contract + shared codeinterface + embedded helper typeabstract class — both in one
    Required methodinterface methodabstract public function area(): float;
    Constructor chainingparent::__construct(...)
    Type testtype switch / assertion$x instanceof Shape
    Multiple contractssatisfy many interfaces freelyimplements A, B — many interfaces, one extends

    11. Enums

    ConceptGoPHP
    Declaretype S int + iota const blockenum S: string { case A = 'a'; }
    To raw valuehand-written String()$s->value
    Case name$s->name (e.g. "Pending")
    From raw valuehand-written map/switchS::from($raw) (throws) / S::tryFrom($raw) (null)
    All valuesmanual sliceS::cases()
    Exhaustivenesslinters, maybematch throws on an unhandled case
    Invalid valuesOrderStatus(42) — legalcannot be constructed

    12. Traits

    ConceptGoPHP
    Share method codeembed a structtrait T { ... } + use T;
    How methods arrivepromoted, still the inner type'sflattened in, as if written in the class
    Call back into hostnot possible via embedding$this->method() — dynamic dispatch
    Multiple sourcesembed several structsuse A, B;
    Name clashambiguous selector erroruse A, B { A::f insteadof B; }
    Require host methodsabstract public function name(): string; in the trait
    Stateembedded struct's fieldstraits can declare properties too

    13. array_map, array_filter & Friends

    ConceptGoPHP
    Transformfor range + appendarray_map($fn, $arr)
    Selectfor range + if + appendarray_filter($arr, $fn)
    Foldaccumulator looparray_reduce($arr, $fn, $init)
    Sumaccumulator looparray_sum($arr)
    Inline callbackfunc(p Product) string { … }fn($p) => $p['name']
    Argument ordern/amap: callback first; filter: array first
    Keys after filterslices reindex by naturepreserved — call array_values()
    Sort with comparatorslices.SortFuncusort($arr, $fn) (in place, by reference)

    14. List Assignment & Spread

    ConceptGoPHP
    Multiple assignmenta, b := f()[$a, $b] = f();
    Swapa, b = b, a[$a, $b] = [$b, $a];
    Skip a value_, b := f()[, $b] = f();
    Pick named fields['name' => $n] = $user;
    Variadic parameterfunc f(nums ...int)function f(int ...$nums)
    Spread at call sitef(nums...) (dots after)f(...$nums) (dots before)
    Concatenateappend(a, b...)[...$a, ...$b]
    Destructure in a loopfor _, p := range pairsforeach ($pairs as [$x, $y])

    15. Closures & Callables

    ConceptGoPHP
    Anonymous functionfunc(x int) int { ... }function (int $x) { ... }
    Capture a variableimplicit, by referenceuse ($n) — explicit, by value (snapshot)
    Capture by referencethe only modeuse (&$n) — opt-in per variable
    Short single expressionfn($x) => $x * $n (auto-captures by value)
    Function-typed parameterf func(int) intcallable $f / Closure $f
    Function-typed returnfunc() intClosure
    Named function as a valuestrings.ToUpperstrtoupper(...) (first-class callable) or 'strtoupper'

    16. Exceptions & Error Handling

    ConceptGoPHP
    Signal failurereturn 0, errthrow new SomeException("msg");
    Propagate upwardif err != nil { return 0, err } everywhereautomatic — do nothing
    Handle by typeerrors.As(err, &target)catch (SomeException $e) — subclasses match too
    Custom errortype with Error() stringclass MyError extends Exception {}
    Guaranteed cleanupdeferfinally { ... }
    The messageerr.Error()$e->getMessage()
    Catch anythingrecover()catch (Throwable $e)

    17. Static, Constants & readonly

    ConceptGoPHP
    Constantconst DefaultName = "guest"const DEFAULT_NAME = "guest"; in a class
    Access itpkg.DefaultNameConfig::DEFAULT_NAME
    Shared statevar count intprivate static int $count = 0;
    Call without instancepkg.Increment()Counter::increment()
    Self-referenceunqualified name in packageself::$count, self::CONST
    Write-once field— (convention only)public readonly string $name
    Violation caughtneverError thrown at runtime

    18. Generators & Iterables

    ConceptGo 1.23PHP
    Define an iteratorfunc(yield func(int) bool)any function containing yield
    Produce a valueif !yield(v) { return }yield $v;
    Return typeiter.Seq[int]Generator
    Consumefor v := range seqforeach ($gen as $v)
    Early stopbreak → yield returns falsebreak — generator stays suspended
    Collect allslices.Collect(seq)iterator_to_array($gen)
    Array-or-sequence paramtwo signatures (or convert)iterable accepts both

    19. Working with JSON

    ConceptGoPHP
    Serializejson.Marshal(v)json_encode($v)
    Parsejson.Unmarshal(raw, &v)json_decode($raw, true)
    Field namingjson:"snake_name" tagsarray keys are used verbatim
    Missing fieldzero valuekey absent — read with ?? $default
    Bad inputerr != nilnull silently, or JSON_THROW_ON_ERRORJsonException
    Pretty outputjson.MarshalIndentjson_encode($v, JSON_PRETTY_PRINT)
    Objects instead of arraysomit the truestdClass

    20. Capstone

    ConceptGoPHP
    Copying a collection of objects[]*Item copy shares the pointeesarray copy shares the objects
    Shallow copy of one objectcopied := *it$copy = clone $it;
    Maybe-absent result*Item, check nil?Item, check null (or chain with ?->)
    Sum a fieldfor loop + accumulatorarray_reduce($items, fn(...), 0)
    Transformfor loop building a new slicearray_map(fn($it) => ..., $items)
    Select + reindexfor loop with appendarray_values(array_filter(...))
    Deep-copy hookwrite it by hand__clone() method, called on clone