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.
letretstr: VarExportResult = '' let iret = '' let value = '' let cnt = 0 constx: 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)' }
let retstr = '' let iret = '' let value = '' let cnt = 0 const x = [] // We use the last argument (not part of PHP) to pass in // our indentation level let innerIndent = '' let outerIndent = '' const getFuncName = function (fn) { const name = /\W*function\s+([\w$]+)\s*\(/.exec(fn.toString()) if (!name) { return'(Anonymous)' } return name[1] ?? '(Anonymous)' }
const _isNormalInteger = function (input) { const number = Math.floor(Number(input)) return number !== Infinity && String(number) === input && number >= 0 }
const _makeIndent = function (indentLevel) { returnnewArray(Math.max(indentLevel, 0) + 1).join(' ') } const __getType = function (inp) { let i = 0 let match = null let cons = '' const types = ['boolean', 'number', 'string', 'array'] const jsType = typeof inp let type = 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)
functionecho(...args: EchoValue[]): void { // discuss at: https://locutus.io/php/echo/ // parity verified: PHP 8.3 // original by: Philip Peterson // improved by: echo is bad // improved by: Nate // improved by: Brett Zamir (https://brett-zamir.me) // improved by: Brett Zamir (https://brett-zamir.me) // improved by: Brett Zamir (https://brett-zamir.me) // revised by: Der Simon (https://innerdom.sourceforge.net/) // bugfixed by: Eugene Bulkin (https://doubleaw.com/) // bugfixed by: Brett Zamir (https://brett-zamir.me) // bugfixed by: Brett Zamir (https://brett-zamir.me) // bugfixed by: EdorFaus // note 1: In 1.3.2 and earlier, this function wrote to the body of the document when it // note 1: was called in webbrowsers, in addition to supporting XUL. // note 1: This involved >100 lines of boilerplate to do this in a safe way. // note 1: Since I can't imageine a complelling use-case for this, and XUL is deprecated // note 1: I have removed this behavior in favor of just calling `console.log` // note 2: You'll see functions depends on `echo` instead of `console.log` as we'll want // note 2: to have 1 contact point to interface with the outside world, so that it's easy // note 2: to support other ways of printing output. // revised by: Kevin van Zonneveld (https://kvz.io) // input by: JB // example 1: echo('Hello world') // returns 1: undefined
returnconsole.log(args.join(' ')) }
// php/var/var_export (target function module) typeVarExportInput = PhpRuntimeValue
letretstr: VarExportResult = '' let iret = '' let value = '' let cnt = 0 constx: 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)' }
// php/_helpers/_phpTypes (Locutus helper dependency) functionisPhpArrayObject(value) { returntypeof value === 'object' && value !== null }
functiontoPhpArrayObject(value) { if (isPhpArrayObject(value)) { return value }
return {} }
// php/_helpers/_phpRuntimeState (Locutus helper dependency) functiongetPhpObjectEntry(value, key) { if ((typeof value !== 'object' && typeof value !== 'function') || value === null) { returnundefined }
let current = value while (current) { const descriptor = Object.getOwnPropertyDescriptor(current, key) if (descriptor) { if (typeof descriptor.get === 'function') { const getterValue = descriptor.get.call(value) returntypeof getterValue === 'undefined' ? undefined : getterValue } const directValue = descriptor.value returntypeof directValue === 'undefined' ? undefined : directValue } current = Object.getPrototypeOf(current) }
returnundefined }
// php/strings/echo (Locutus dependency module) functionecho(...args) { // discuss at: https://locutus.io/php/echo/ // parity verified: PHP 8.3 // original by: Philip Peterson // improved by: echo is bad // improved by: Nate // improved by: Brett Zamir (https://brett-zamir.me) // improved by: Brett Zamir (https://brett-zamir.me) // improved by: Brett Zamir (https://brett-zamir.me) // revised by: Der Simon (https://innerdom.sourceforge.net/) // bugfixed by: Eugene Bulkin (https://doubleaw.com/) // bugfixed by: Brett Zamir (https://brett-zamir.me) // bugfixed by: Brett Zamir (https://brett-zamir.me) // bugfixed by: EdorFaus // note 1: In 1.3.2 and earlier, this function wrote to the body of the document when it // note 1: was called in webbrowsers, in addition to supporting XUL. // note 1: This involved >100 lines of boilerplate to do this in a safe way. // note 1: Since I can't imageine a complelling use-case for this, and XUL is deprecated // note 1: I have removed this behavior in favor of just calling `console.log` // note 2: You'll see functions depends on `echo` instead of `console.log` as we'll want // note 2: to have 1 contact point to interface with the outside world, so that it's easy // note 2: to support other ways of printing output. // revised by: Kevin van Zonneveld (https://kvz.io) // input by: JB // example 1: echo('Hello world') // returns 1: undefined
let retstr = '' let iret = '' let value = '' let cnt = 0 const x = [] // We use the last argument (not part of PHP) to pass in // our indentation level let innerIndent = '' let outerIndent = '' const getFuncName = function (fn) { const name = /\W*function\s+([\w$]+)\s*\(/.exec(fn.toString()) if (!name) { return'(Anonymous)' } return name[1] ?? '(Anonymous)' }
const _isNormalInteger = function (input) { const number = Math.floor(Number(input)) return number !== Infinity && String(number) === input && number >= 0 }
const _makeIndent = function (indentLevel) { returnnewArray(Math.max(indentLevel, 0) + 1).join(' ') } const __getType = function (inp) { let i = 0 let match = null let cons = '' const types = ['boolean', 'number', 'string', 'array'] const jsType = typeof inp let type = 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)
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.