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

Design functions so errors are obvious at the call site

In PHP you often throw exceptions or return null and hope callers check. Error-first design returns a structured result: success with data, or failure with a reason — especially in JavaScript helpers that feed UI code.

PHP habit

<?php
function parsePort(string $value): array {
    if ($value === '') {
        return ['ok' => false, 'error' => 'Port required'];
    }
    if (!ctype_digit($value)) {
        return ['ok' => false, 'error' => 'Port must be a number'];
    }
    $port = (int) $value;
    if ($port < 1 || $port > 65535) {
        return ['ok' => false, 'error' => 'Port out of range'];
    }
    return ['ok' => true, 'port' => $port];
}
// Alternative: throw — fine in domain layers with try/catch upstream
function parsePortStrict(string $value): int {
    $result = parsePort($value);
    if (!$result['ok']) {
        throw new InvalidArgumentException($result['error']);
    }
    return $result['port'];
}

JavaScript equivalent

function parsePort(value) {
  if (value === '' || value == null) {
    return { ok: false, error: 'Port required' };
  }
  const n = Number(value);
  if (Number.isNaN(n)) {
    return { ok: false, error: 'Port must be a number' };
  }
  if (n < 1 || n > 65535) {
    return { ok: false, error: 'Port out of range' };
  }
  return { ok: true, port: n };
}

function applyPort(config, raw) {
  const result = parsePort(raw);
  if (!result.ok) {
    return { ...config, portError: result.error };
  }
  return { ...config, port: result.port, portError: null };
}
Approach Good for
{ ok, error } return Form validation, fetch wrappers, UI branches
throw new Error(...) Unexpected bugs, programmer mistakes
null with no shape Easy to forget checks — avoid in new code

Caller habit

const result = parsePort(userInput);
if (!result.ok) {
  showMessage(result.error);
  return;
}
connect(result.port);

Same shape as checking $result['ok'] in PHP before using $result['port'].

Failure mode: mixing styles

Returning { ok: false } sometimes and throwing other times forces callers to handle both paths. Pick a layer convention: error objects at UI boundaries, throws inside domain code that always has a try/catch, for example.

Try it

Use the amber Try it panel below. Click Run.

const inputs = ['', 'abc', '8080', '99999'];
for (const raw of inputs) {
  const next = applyPort({ host: 'localhost' }, raw);
  console.log(raw, next.port ?? '—', next.portError ?? 'ok');
}

Invalid ports should log an error string; 8080 should show a numeric port and ok.

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