Originally published on php-to-js.learnio.dev — part of the PHP to JavaScript course. View this lesson on the original site.

Closures let inner functions remember outer variables

A closure is a function that still sees variables from the scope where it was created. PHP needs use ($x); JavaScript captures automatically — essential for callbacks and factories.

PHP habit

<?php
function makeMultiplier(float $factor): Closure {
    return function (float $x) use ($factor): float {
        return $x * $factor;
    };
}

$double = makeMultiplier(2);
echo $double(5); // 10

JavaScript equivalent

function makeMultiplier(factor) {
  return function (x) {
    return x * factor;
  };
}

const double = makeMultiplier(2);
console.log(double(5)); // 10
PHP JavaScript
use ($factor) Automatic capture
use (&$count) for reference Reassign outer let in closure
Returning anonymous function Returning function expression

Real callback: run later

function later(fn) {
  setTimeout(fn, 0);
}

let count = 0;
later(() => {
  count += 1;
  console.log('count inside callback', count);
});
console.log('scheduled, count now', count);

The callback closes over count. PHP does not schedule like this in the request cycle — the browser or Node event loop does.

Factory with private state

function makeCounter() {
  let value = 0;
  return {
    inc() { value += 1; return value; },
    read() { return value; },
  };
}

const a = makeCounter();
const b = makeCounter();
console.log(a.inc(), a.inc(), b.inc()); // 1, 2, 1

Each call to makeCounter gets its own value cell — like separate closure instances in PHP.

Try it

Use the amber Try it panel below. Click Run.

const mult = makeMultiplier(3);
const prices = [10, 20, 30];
const scaled = prices.map((p) => mult(p));
console.log(scaled);

const counter = makeCounter();
console.log(counter.inc(), counter.inc());

You should see [30, 60, 90] and 1 then 2. That is closure + callback shape in everyday code.

From PHP to JavaScript — Control Flow, Functions, and Scope