PHP's var_export in TypeScript

How to use

Install via yarn add locutus and import: import { var_export } from 'locutus/php/var/var_export'.

Or with CommonJS: const { var_export } = require('locutus/php/var/var_export')

Use a bundler that supports tree-shaking so you only ship the functions you actually use. Vite, webpack, Rollup, and Parcel all handle this. For server-side use this is less of a concern.

Examples

These examples are extracted from test cases that automatically verify our functions against their native counterparts.

#codeexpected result
1var_export(null)null
2var_export({0: 'Kevin', 1: 'van', 2: 'Zonneveld'}, true)"array (\n 0 => 'Kevin',\n 1 => 'van',\n 2 => 'Zonneveld',\n)"
3var data = 'Kevin' var_export(data, true)"'Kevin'"
4var_export({0: 'Kevin', 1: 'van', 'lastName': 'Zonneveld'}, true)"array (\n 0 => 'Kevin',\n 1 => 'van',\n 'lastName' => 'Zonneveld',\n)"
5var_export([], true)"array (\n)"
6var_export({ test: [ 'a', 'b' ] }, true)"array (\n 'test' => \n array (\n 0 => 'a',\n 1 => 'b',\n ),\n)"

Dependencies

This function uses the following Locutus functions:

Here's what our current TypeScript equivalent to PHP's var_export looks like.

import { getPhpObjectEntry } from '../_helpers/_phpRuntimeState.ts'
import { type PhpRuntimeValue, toPhpArrayObject } from '../_helpers/_phpTypes.ts'
import { echo } from '../strings/echo.ts'

type VarExportInput = PhpRuntimeValue

type VarExportType =
| 'resource'
| 'function'
| 'null'
| 'array'
| 'object'
| 'string'
| 'number'
| 'boolean'
| 'undefined'
type VarExportResult = string | number | boolean | null

export function var_export(mixedExpression: VarExportInput, boolReturn: true, idtLevel?: number): VarExportResult
export function var_export(mixedExpression: VarExportInput, boolReturn?: false | undefined, idtLevel?: number): null
export function var_export(
mixedExpression: VarExportInput,
boolReturn?: boolean,
idtLevel?: number,
): VarExportResult | null
export function var_export(
mixedExpression: VarExportInput,
boolReturn?: boolean,
idtLevel = 2,
): VarExportResult | null {
// discuss at: https://locutus.io/php/var_export/
// original by: Philip Peterson
// improved by: johnrembo
// improved by: Brett Zamir (https://brett-zamir.me)
// input by: Brian Tafoya (https://www.premasolutions.com/)
// input by: Hans Henrik (https://hanshenrik.tk/)
// bugfixed by: Brett Zamir (https://brett-zamir.me)
// bugfixed by: Brett Zamir (https://brett-zamir.me)
// bugfixed by: simivar (https://github.com/simivar)
// bugfixed by: simivar (https://github.com/simivar)
// bugfixed by: simivar (https://github.com/simivar)
// example 1: var_export(null)
// returns 1: null
// example 2: var_export({0: 'Kevin', 1: 'van', 2: 'Zonneveld'}, true)
// returns 2: "array (\n 0 => 'Kevin',\n 1 => 'van',\n 2 => 'Zonneveld',\n)"
// example 3: var data = 'Kevin'
// example 3: var_export(data, true)
// returns 3: "'Kevin'"
// example 4: var_export({0: 'Kevin', 1: 'van', 'lastName': 'Zonneveld'}, true)
// returns 4: "array (\n 0 => 'Kevin',\n 1 => 'van',\n 'lastName' => 'Zonneveld',\n)"
// example 5: var_export([], true)
// returns 5: "array (\n)"
// example 6: var_export({ test: [ 'a', 'b' ] }, true)
// returns 6: "array (\n 'test' => \n array (\n 0 => 'a',\n 1 => 'b',\n ),\n)"

let retstr: VarExportResult = ''
let iret = ''
let value = ''
let cnt = 0
const x: string[] = []
// We use the last argument (not part of PHP) to pass in
// our indentation level
let innerIndent = ''
let outerIndent = ''
const getFuncName = function (fn: { toString: () => string }): string {
const name = /\W*function\s+([\w$]+)\s*\(/.exec(fn.toString())
if (!name) {
return '(Anonymous)'
}
return name[1] ?? '(Anonymous)'
}

const _isNormalInteger = function (input: string): boolean {
const number = Math.floor(Number(input))
return number !== Infinity && String(number) === input && number >= 0
}

const _makeIndent = function (indentLevel: number): string {
return new Array(Math.max(indentLevel, 0) + 1).join(' ')
}
const __getType = function (inp: VarExportInput): VarExportType | null {
let i = 0
let match: RegExpMatchArray | null = null
let cons = ''
const types: Array<'boolean' | 'number' | 'string' | 'array'> = ['boolean', 'number', 'string', 'array']
const jsType = typeof inp
let type: VarExportType | null =
jsType === 'boolean' ||
jsType === 'number' ||
jsType === 'string' ||
jsType === 'function' ||
jsType === 'undefined' ||
jsType === 'object'
? jsType
: null
if (type === 'object' && typeof inp === 'object' && inp !== null) {
const constructorValue = getPhpObjectEntry(inp, 'constructor')
if (typeof constructorValue === 'function' && getFuncName(constructorValue) === 'LOCUTUS_Resource') {
return 'resource'
}
}
if (type === 'function') {
return 'function'
}
if (type === 'object' && !inp) {
// Should this be just null?
return 'null'
}
if (type === 'object' && typeof inp === 'object' && inp !== null) {
const constructorValue = getPhpObjectEntry(inp, 'constructor')
if (typeof constructorValue !== 'function') {
return 'object'
}
cons = constructorValue.toString()
match = cons.match(/(\w+)\(/)
if (match) {
cons = (match[1] ?? '').toLowerCase()
}
for (i = 0; i < types.length; i++) {
const knownType = types[i]
if (knownType && cons === knownType) {
type = knownType
break
}
}
}
return type
}
const type = __getType(mixedExpression)

if (type === null) {
retstr = 'NULL'
} else if (type === 'array' || type === 'object') {
const source = toPhpArrayObject<VarExportInput>(mixedExpression)
outerIndent = _makeIndent(idtLevel - 2)
innerIndent = _makeIndent(idtLevel)
for (const [key, entry] of Object.entries(source)) {
value = ' '
const subtype = __getType(entry)
if (subtype === 'array' || subtype === 'object' || subtype === 'function') {
value = ' \n'
}
value += String(var_export(entry, true, idtLevel + 2))
const mappedKey = _isNormalInteger(key) ? key : `'${key}'`
x[cnt++] = innerIndent + mappedKey + ' =>' + value
}
if (x.length > 0) {
iret = x.join(',\n') + ',\n'
}
retstr = outerIndent + 'array (\n' + iret + outerIndent + ')'
} else if (type === 'function') {
// PHP deprecated create_function() in 7.2 and removed it in 8.0.
// On our PHP 8.3 parity target, closures export as \Closure::__set_state(array()).
outerIndent = _makeIndent(idtLevel - 2)
retstr = outerIndent + '\\Closure::__set_state(array(\n' + outerIndent + '))'
} else if (type === 'resource') {
// Resources treated as null for var_export
retstr = 'NULL'
} else {
if (typeof mixedExpression === 'string') {
retstr = "'" + mixedExpression.replace(/([\\'])/g, '\\$1').replace(/\0/g, '\\0') + "'"
} else if (mixedExpression === null) {
retstr = null
} else if (typeof mixedExpression === 'number') {
retstr = Number(mixedExpression)
} else if (typeof mixedExpression === 'boolean') {
retstr = Boolean(mixedExpression)
} else {
retstr = String(mixedExpression)
}
}

if (!boolReturn) {
echo(retstr)
return null
}

return retstr
}

Improve this function

Locutus is a community effort following The McDonald's Theory: we ship first iterations, hoping others will improve them. If you see something that could be better, we'd love your contribution.

View on GitHub · Edit on GitHub · View Raw


« More PHP var functions


Star