Documentation
¶
Index ¶
- Constants
- func AcceptsHTML(accept string) bool
- func Bindings() []func(*Runtime)
- func DeepSize(v any, visited visitedSet) int64
- func EnvFromContext(ctx context.Context) (map[string]string, bool)
- func EstimateValueSize(v any) int64
- func Lookup[T any](rt *Runtime, symName string) (T, error)
- func RegisterBinding(installer func(*Runtime))
- func ScopeBuiltins() []string
- func ScriptEnvironment(environment []string) map[string]string
- func WantsErrorPage(r *http.Request) bool
- func WithRoutePattern(ctx context.Context, pattern string) context.Context
- type ArgumentCountError
- type ArithmeticError
- type Callable
- type Context
- func (c Context) AddResponseHeader(name, value string)
- func (c Context) Answered(body []byte) bool
- func (c Context) Cleanup()
- func (c Context) CookieMap() map[string]string
- func (c Context) Errors() []error
- func (c Context) FileMap() map[string][]*UploadedFile
- func (c Context) GetAllHeaders() *model.Array
- func (c Context) GetMap() map[string]string
- func (c Context) HTTPResponseCode(sapi string, opts ...any) any
- func (c Context) Header(header string, opts ...any)
- func (c Context) HeaderMap() map[string]string
- func (c Context) IsUpload(path string) bool
- func (c Context) PostMap() map[string]string
- func (c Context) RawBody() []byte
- func (c Context) Register(rt *Runtime)
- func (c Context) ResponseHeaders() http.Header
- func (c Context) ResponseStatus() int
- func (c Context) ServerMap() *mapmap.MapMap
- func (c Context) SetDefaultHeader(name, value string)
- func (c Context) SetRawBody(body []byte)
- func (c Context) StatusFor(err error) int
- func (c Context) WriteResponse(w http.ResponseWriter, status int, body []byte)
- type DivisionByZeroError
- type ExitError
- type ExprCache
- type FileMode
- type FilenameObserver
- type FuncSite
- type HostPanicError
- type IncludeCache
- type IncludeFunc
- type IncludeObserver
- type InfoField
- type InfoSection
- type LookupError
- type Observer
- type Options
- type Pool
- type Precompiler
- type RedeclareError
- type Runtime
- func (rt *Runtime) AccountRequest(values ...any)
- func (rt *Runtime) AsCallable(v any) (*Callable, error)
- func (rt *Runtime) Callable(v any) (func(...any) (any, error), bool)
- func (rt *Runtime) ClassExists(name string, autoload bool) (bool, error)
- func (rt *Runtime) ClientContext() context.Context
- func (rt *Runtime) CompiledTree() (programs, expressions int, heap int64)
- func (rt *Runtime) ConnectionAborted() bool
- func (rt *Runtime) Const(name string) (any, bool)
- func (rt *Runtime) Context() context.Context
- func (rt *Runtime) Database() model.DatabaseProvider
- func (rt *Runtime) DeclaredClasses() []string
- func (rt *Runtime) DeclaredPrograms() map[*model.Program]string
- func (rt *Runtime) DefinedConstants() map[string]any
- func (rt *Runtime) DefinedFunctions() (internal, user []string)
- func (rt *Runtime) EnterRequest(ctx context.Context) func()
- func (rt *Runtime) Eval(e model.Expr, scope *Scope) (any, error)
- func (rt *Runtime) Exit(code int) error
- func (rt *Runtime) FS() fs.FS
- func (rt *Runtime) Fork(w io.Writer) *Runtime
- func (rt *Runtime) FreezeStdlib()
- func (rt *Runtime) FunctionExists(name string) bool
- func (rt *Runtime) HasErrorHandler() bool
- func (rt *Runtime) IgnoreUserAbort() bool
- func (rt *Runtime) IncludeFile(path string) (any, error)
- func (rt *Runtime) IncludePath() string
- func (rt *Runtime) IncludedFiles() []string
- func (rt *Runtime) InterfaceExists(name string, autoload bool) (bool, error)
- func (rt *Runtime) InvokeClosure(decl *model.Closure, args ...any) (any, error)
- func (rt *Runtime) InvokeNamed(name string, args ...any) (any, error)
- func (rt *Runtime) Load(src string) (*model.Program, error)
- func (rt *Runtime) LoadFile(path string) (*model.Program, error)
- func (rt *Runtime) LookupConstructor(name string) (any, bool)
- func (rt *Runtime) LookupFunc(name string) (any, bool)
- func (rt *Runtime) Mail() model.MailProvider
- func (rt *Runtime) MemoryLimit() Size
- func (rt *Runtime) MemoryPeak() int64
- func (rt *Runtime) MemoryUsage() int64
- func (rt *Runtime) MemoryWalk() int64
- func (rt *Runtime) MethodExists(class, method string) bool
- func (rt *Runtime) Observe(observer Observer)
- func (rt *Runtime) OnError(fn func(error))
- func (rt *Runtime) Output() io.Writer
- func (rt *Runtime) OutputDepth() int
- func (rt *Runtime) PHPInfo() error
- func (rt *Runtime) PopOutput() bool
- func (rt *Runtime) Precompiled() bool
- func (rt *Runtime) PushOutput(w io.Writer)
- func (rt *Runtime) RecordError(err error)
- func (rt *Runtime) RegisterAutoloader(callback any, prepend bool)
- func (rt *Runtime) RegisterClass(c *model.Class)
- func (rt *Runtime) RegisterConstructor(name string, ctor any)
- func (rt *Runtime) RegisterFunc(name string, fn any)
- func (rt *Runtime) RegisterInclude(path string, fn func() (any, error))
- func (rt *Runtime) RegisterInfo(name string, section InfoSection)
- func (rt *Runtime) RegisterShutdown(callback any)
- func (rt *Runtime) Reset(out io.Writer, stdin io.Reader)
- func (rt *Runtime) ResetSession(out io.Writer, stdin io.Reader)
- func (rt *Runtime) ResolvePath(p string) string
- func (rt *Runtime) Run(p *model.Program) (err error)
- func (rt *Runtime) SAPI() string
- func (rt *Runtime) SPLAutoload(class string) error
- func (rt *Runtime) SetConst(name string, val any)
- func (rt *Runtime) SetContext(ctx context.Context)
- func (rt *Runtime) SetCoverage(c *coverage.Collector)
- func (rt *Runtime) SetExprCache(cache *ExprCache)
- func (rt *Runtime) SetGlobal(name string, val any)
- func (rt *Runtime) SetIgnoreUserAbort(enable bool)
- func (rt *Runtime) SetIncludeCache(cache *IncludeCache)
- func (rt *Runtime) SetIncludePath(value string) string
- func (rt *Runtime) SetIncludeResolver(fn IncludeFunc)
- func (rt *Runtime) SetPreparer(prepare func(*Runtime))
- func (rt *Runtime) SetTimeLimit(limit time.Duration)
- func (rt *Runtime) SetWorkDir(dir string) bool
- func (rt *Runtime) Stdin() io.Reader
- func (rt *Runtime) TimeLimit() time.Duration
- func (rt *Runtime) Trace(message string, kind ...telemetry.Kind) *telemetry.Span
- func (rt *Runtime) UnregisterAutoloader(callback any) bool
- func (rt *Runtime) UpdateFilename(filename string)
- func (rt *Runtime) UpdateIncludedFiles(count int)
- func (rt *Runtime) UpdateStatus(state telemetry.State)
- func (rt *Runtime) UploadFileMode() FileMode
- func (rt *Runtime) WorkDir() string
- func (rt *Runtime) WorkDirPath() string
- func (rt *Runtime) WritablePaths() []string
- type RuntimeException
- type Scope
- type Size
- type Throwable
- type TimeLimitError
- type TypeError
- type UndefinedConstantError
- type UploadedFile
Examples ¶
Constants ¶
const ( UploadErrOK = 0 UploadErrIniSize = 1 UploadErrNoFile = 4 UploadErrNoTmpDir = 6 UploadErrCantWrite = 7 )
PHP's UPLOAD_ERR_* codes, as they appear in a $_FILES entry. Only the ones this runtime can produce are named; 2, 3 and 8 come from a per-form limit and from extensions that phpscript has no equivalent of.
const DefaultMaxCacheSize = 10000
DefaultMaxCacheSize is the default upper bound on cached entries.
const DefaultQueue = 1024
DefaultQueue is how many runs a pool holds waiting for a worker. It is deep enough that a burst does not block the caller that produced it and shallow enough that a queue this long means the workers are not keeping up, which is a thing to find out rather than to absorb.
const DefaultUploadFileMode = FileMode(0o644)
DefaultUploadFileMode is the mode move_uploaded_file() gives a stored upload when the configuration does not name one. The temporary copy an upload arrives in is private to this process, so a mode has to be applied on the way out or nothing else could read what the script stored.
const InfrastructurePrefix = "PLATFORM_"
InfrastructurePrefix names the variables that configure phpscript and the platform it runs on: connection strings, the listen address, the telemetry block. They are the host's configuration and getenv() does not answer them, which is what keeps a tenant out of the operator's connection strings.
Variables ¶
This section is empty.
Functions ¶
func AcceptsHTML ¶ added in v0.3.3
AcceptsHTML reports whether an Accept header explicitly names HTML.
Explicitly is the whole point. "*/*" is what curl and fetch() send and it matches every type there is, so reading it as a request for HTML would put a website's error page in front of every program that talks to the server. Only text/html and application/xhtml+xml, written out and not weighted to zero, count; so does neither a "text/*" wildcard nor an absent header.
func Bindings ¶ added in v0.2.4
func Bindings() []func(*Runtime)
Bindings returns the contributed installers in registration order.
func DeepSize ¶ added in v0.3.3
DeepSize estimates the bytes held by a PHP value, recursing into script-owned containers. A container already in visited costs nothing. Native Go values returned by bindings are host-owned and get a shallow size, the same ownership rule flatHost.SetEntry applies.
func EnvFromContext ¶ added in v0.2.0
EnvFromContext returns the request-scoped environment attached to contexts auto-injected into registered Go callables.
func EstimateValueSize ¶ added in v0.3.3
EstimateValueSize is a shallow estimate of what a value costs, in bytes: a scalar or string is its own size, a collection is its header plus one level of entries, and anything else is the shallow sizeof. It is cheap enough to run on every binding's result, and it undercounts a deeper graph on purpose - the walk that does not is DeepSize.
func Lookup ¶ added in v0.6.0
Lookup resolves symName to a PHP function and returns it as T, a Go function type. It is plugin.Lookup over a source tree.
T returns at most one value and an optional trailing error, checked here rather than at the call. A name matching nothing, or more than one declaration, is a *LookupError naming what it matched. The returned function belongs to rt, which serves one goroutine.
docs/use-cases/entrypoints.md is the surface, with the example.
func RegisterBinding ¶ added in v0.2.4
func RegisterBinding(installer func(*Runtime))
RegisterBinding contributes a runtime installer, which stdlib.Register runs on every Runtime it sets up. Binding packages call it from their init() (see stdlib/core/defer.go), so a package is wired in by importing it, the way a program imports a database/sql driver. The registry lives here, in the leaf package that owns Runtime, so that stdlib can blank-import its subpackages without the two importing each other.
Installers run in registration order, before the bindings a host passes to stdlib.Register directly.
func ScopeBuiltins ¶ added in v0.5.0
func ScopeBuiltins() []string
ScopeBuiltins names the builtins provided per-environment instead of through the function table. function_exists() and the linter both ask the function table, which does not carry these, so a script calling one reads as a call to something undefined without this list.
func ScriptEnvironment ¶ added in v0.3.1
ScriptEnvironment returns the environment scripts read with getenv().
A nil environment means the process environment, which is what a CLI run has. A host that configured one passes it instead, and a virtual host always does, so that a site sees the variables it declared rather than everything the operator's process happens to carry. Either way the infrastructure variables are held back.
func WantsErrorPage ¶ added in v0.3.3
WantsErrorPage reports whether a request is a browser navigation, the only kind of request a site's HTML error page is meant for. A HEAD request is never one: there is no body to render a page into.
A URL prefix cannot answer this, because an API and a website share one URL space and one catch-all handler; the request answers it itself. Sec-Fetch-Dest is decisive when a browser sends it: fetch() and XHR send "empty", an image "image", a stylesheet "style", and only a navigation "document". A client that sends none is judged by whether its Accept header explicitly names HTML.
func WithRoutePattern ¶ added in v0.4.0
WithRoutePattern records the @route path a request matched, before any router-specific rewriting. The path values $_REQUEST carries are built from it.
Without it the pattern has to be recovered from r.Pattern, which is the router's own dialect: chi reports /c/* for a route declared /c/{tail...}, and the name the value should be exported under is not in there.
Types ¶
type ArgumentCountError ¶ added in v0.3.0
ArgumentCountError reports a call that passed more arguments than the callable declares. PHP raises the same condition under the same name, so it names that class: `catch (ArgumentCountError $e)` and `catch (Error $e)` match it and `catch (Exception $e)` does not, as in PHP.
func (*ArgumentCountError) Error ¶ added in v0.3.0
func (e *ArgumentCountError) Error() string
Error is php's wording, and says "at most" because a binding spells PHP's optional parameters as extra ones: too few arguments is legal and zero-padded.
func (*ArgumentCountError) ThrowableClass ¶ added in v0.3.4
func (e *ArgumentCountError) ThrowableClass() string
ThrowableClass names the PHP class, implementing Throwable.
type ArithmeticError ¶ added in v0.3.3
type ArithmeticError struct {
Message string
}
ArithmeticError reports an operation PHP 8 rejects with the class of the same name: a shift by a negative number is the one this runtime raises. It names its PHP class, and a clause matches on that name, so `catch (ArithmeticError $e)` matches it exactly and `catch (Error $e)` matches it on the name's suffix, while `catch (Exception $e)` does not, as in PHP.
func (*ArithmeticError) Error ¶ added in v0.3.3
func (e *ArithmeticError) Error() string
Error renders the message PHP carries on the same operation.
func (*ArithmeticError) ThrowableClass ¶ added in v0.3.4
func (e *ArithmeticError) ThrowableClass() string
ThrowableClass names the PHP class, implementing Throwable.
type Callable ¶ added in v0.6.0
type Callable struct {
// contains filtered or unexported fields
}
Callable is a php callable as a runtime value: one declaration to run, and what it is bound to. It covers a closure literal, a method bound to the receiver it was read off, and a declared function held by name, which is what php's Closure covers and what a script sees it as.
docs/GLOSSARY.md records the word and docs/design.md the re-entry rule it exists for: the value crosses to another runtime and the execution does not.
func (*Callable) Call ¶ added in v0.6.0
Call invokes the callable on the runtime that built it, which is what a script calling one means: `($this->fn)(...)` is the call `$this->fn(...)` makes.
func (*Callable) Captures ¶ added in v0.6.0
Captures reports whether the callable took anything from where it was written: a closure's `use (...)` clause or the `$this` one written inside a method binds, and the receiver a bound method reads its properties off.
It is the question a host asks before running one somewhere else. A callable that captures nothing is a function of its arguments, and a function of its arguments runs anywhere: a declared function held by name and a Class::method spelling, whose receiver is an empty instance built per call, both answer false.
func (*Callable) Invoke ¶ added in v0.6.0
Invoke runs the callable on rt, in a scope holding args and nothing else - and, for a bound method, the receiver it was read off.
It is the cross-runtime call, and it is deliberately not Call: a request is answered on a runtime of its own, and what crosses is the declaration rather than the runtime the value was built on. A name crosses as a name, so the runtime running it resolves it against its own function table.
type Context ¶
type Context struct {
Get map[string]string
Post map[string]string
Path map[string]string
Cookie map[string]string
Server map[string]string
Env map[string]string
Headers map[string]string
Argv []string
// ServerSource is what $_SERVER reads through when the names it holds can
// be answered without a map. A request answers most of them itself, so
// serving one fills Server with the few it cannot and leaves the rest to
// be derived on the first read that asks for them.
//
// Nil reads Server alone, which is what a run with no request behind it
// has. A host setting keys on Server is answered either way: they are the
// source's extras, and an extra wins over a derived name.
ServerSource mapmap.Source
// GetVars, PostVars and CookieVars are the same fields decoded through
// PHP's bracket syntax, and seed $_GET, $_POST and $_COOKIE.
//
// The flat maps above are not the same information. They hold one string
// per literal field name, which is what a Go host reads and what
// Session\Manager looks a cookie up in, and they cannot express what the
// decoder needs: `a[]=1&a[]=2` is one repeated name, so a map keeps only
// the second value.
//
// Nil when the Context was not built from a request; Register falls back
// to the flat map, so a host that fills c.Get itself is unaffected.
GetVars *model.Array
PostVars *model.Array
CookieVars *model.Array
// Files holds the file parts of a multipart body keyed by form field name,
// in the order they were sent. A field carries more than one file when the
// form repeats it, which HTML spells as a "name[]" field.
Files map[string][]*UploadedFile
// contains filtered or unexported fields
}
Context carries HTTP request data exposed to PHP as superglobals, header functions, and staged response headers.
Example ¶
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"github.com/titpetric/phpscript/runner"
)
func main() {
req := httptest.NewRequest(http.MethodGet, "/users/42?tab=profile", nil)
req.Header.Set("X-Request-Id", "abc123")
req.Pattern = "GET /users/{id}"
req.SetPathValue("id", "42")
ctx := runner.FromRequest(req)
ctx.Header("X-Powered-By: phpscript")
fmt.Println(ctx.GetMap()["tab"])
fmt.Println(ctx.Path["id"])
fmt.Println(ctx.HeaderMap()["X-Request-Id"])
fmt.Println(ctx.ResponseHeaders().Get("X-Powered-By"))
}
Output: profile 42 abc123 phpscript
func FromRequest ¶
FromRequest builds a Context from an HTTP request with no size limits on the body. A host that has runtime options, which is every host that reads a configuration file, uses FromRequestOptions instead.
func FromRequestOptions ¶ added in v0.3.1
FromRequestOptions builds a Context from an HTTP request. Path values come out of the matched ServeMux pattern via r.PathValue.
Query, form and cookie fields are recorded twice: flat for a Go host, and decoded for the superglobals. Both keep the last value when a name repeats, as PHP's parser does.
upload_max_filesize and post_max_size limit what the body may carry; max_input_vars and max_input_nesting_level bound what is built from it.
func NewContext ¶
func NewContext() Context
NewContext returns an allocated empty Context value, which is what a host assembling a request by hand writes into: a CLI run, a scheduled job, a test.
func RequestContext ¶ added in v0.2.2
RequestContext returns the request data registered on a runtime context. It is intended for request-aware Go bindings such as session management.
func (Context) AddResponseHeader ¶ added in v0.2.2
AddResponseHeader appends a response header without replacing existing values. It is useful for headers such as Set-Cookie that may occur more than once in a response.
func (Context) Answered ¶ added in v0.3.3
Answered reports whether the script answered this request itself, which a host takes as the script refusing whatever error page the site put up.
A body counts, because a script that echoed something has said what the response is: an endpoint returning 404 with a JSON payload keeps it. So does a Content-Type, because a script that declared what it answers with has declared that it is not answering in HTML, which is a one line opt-out for an endpoint with nothing to put in the body. Neither has anything to do with where the script sits in the URL space, which is the point.
func (Context) Cleanup ¶ added in v0.3.1
func (c Context) Cleanup()
Cleanup removes the temporary files created for the uploaded parts of a request. A host handler defers it for the lifetime of one request; a file the script moved with move_uploaded_file is already gone and is skipped.
func (Context) CookieMap ¶ added in v0.6.0
CookieMap answers the request's cookies, one value per name. Session\Manager reads a session id through it.
func (Context) Errors ¶ added in v0.3.1
Errors returns what the request got wrong before any script ran, which today is a body or a file part refused for its size. A script has no way to catch these: they happened outside it, and the only sign of them it gets is the empty superglobal or the UPLOAD_ERR_INI_SIZE entry they left behind. Register reports each one to the runtime through Runtime.RecordError, so a Go host sees them on the request trace or through Runtime.OnError.
func (Context) FileMap ¶ added in v0.6.0
func (c Context) FileMap() map[string][]*UploadedFile
FileMap answers the file parts of a multipart body, keyed by field name, in the order they were sent.
func (Context) GetAllHeaders ¶
GetAllHeaders implements PHP getallheaders(): an associative array of the incoming request headers keyed by canonical header name.
func (Context) HTTPResponseCode ¶ added in v0.3.3
HTTPResponseCode implements PHP http_response_code([$response_code]).
With no argument it reports the status this response will be sent with, and with one it stages that status and reports the one it replaced.
PHP answers false rather than a number while no status has been chosen, and true rather than a number for the first one set, having none to hand back. On a web SAPI neither happens: a request starts out answering 200. sapi is the SAPI name the runtime runs under, and only the command line, or a host that named no SAPI at all, starts without a status.
func (Context) Header ¶
Header implements PHP header($header[, $replace[, $code]]): it parses a "Name: value" line and stages it on the response header set. replace controls whether an existing header of the same name is overwritten (default true).
func (Context) HeaderMap ¶ added in v0.6.0
HeaderMap answers the request headers by canonical name, building the map on the first call. A request carries a dozen and most pages read none.
func (Context) IsUpload ¶ added in v0.3.1
IsUpload reports whether path is the temporary file of a part of this request. It backs is_uploaded_file() and move_uploaded_file(), which in PHP refuse any path the request did not produce. A path the script has already moved away is no longer one of them, so the copy has to still be there.
func (Context) RawBody ¶ added in v0.4.0
RawBody returns the request body bytes buffered for php://input, if any. A multipart body answers empty, as PHP's php://input does.
func (Context) Register ¶
Register seeds the request superglobals and puts the request itself on the runtime context. After this, PHP reads $_GET, $_POST and $_REQUEST from this Context, and the request-aware functions find it.
The functions themselves - getallheaders(), header(), http_response_code(), setcookie() - are registered by stdlib/http, which reaches this Context through RequestContext at call time. They are registered before this runs, because a host installs the standard library first and seeds the request second; the indirection is what makes that order work either way.
func (Context) ResponseHeaders ¶
ResponseHeaders returns the headers staged by the PHP header() function so a host handler can copy them onto the http.ResponseWriter after execution.
func (Context) ResponseStatus ¶ added in v0.2.0
ResponseStatus returns the status staged by header(), or zero when the host should retain its default status. A Location header defaults to 302 like PHP.
func (Context) ServerMap ¶ added in v0.6.0
ServerMap renders $_SERVER as a view rather than an array.
The names are read through the source, which is the request where there is one, so nothing is copied for a script that reads a key or two and nothing at all for one that reads none. The two times are seeded because PHP answers them as numbers and every other name as a string.
func (Context) SetDefaultHeader ¶ added in v0.3.3
SetDefaultHeader stages a header only if the script did not set one itself. It is how a host applies a default, such as PHP's text/html content type, without overriding what the script said.
func (Context) SetRawBody ¶ added in v0.4.0
SetRawBody stores the bytes php://input answers with, for a host that builds its Context by hand rather than from an *http.Request.
func (Context) StatusFor ¶ added in v0.3.3
StatusFor resolves the HTTP status a finished script ends on, given whatever error it returned. Zero means nothing chose one and the host's default stands.
An uncaught exception is the interesting case. Its code is the script's own number and usually not a status at all, so only a code in the 4xx and 5xx range is taken as one; anything else is an application code and the request failed with a 500. exit() and die() are not failures: a script that ended early still answers with the status it staged, as it does in PHP.
func (Context) WriteResponse ¶ added in v0.3.3
func (c Context) WriteResponse(w http.ResponseWriter, status int, body []byte)
WriteResponse flushes one response: the headers the script staged with header(), the status, and the body it produced. Nothing reaches the ResponseWriter before this, which is what lets a host look at a finished response and answer with something else instead.
A status of zero writes none, leaving net/http its 200. So does a status net/http will not send: it panics on anything outside 100 to 999, and http_response_code() takes whatever number a script hands it.
type DivisionByZeroError ¶ added in v0.3.4
type DivisionByZeroError struct {
Message string
}
DivisionByZeroError reports a division or modulo by zero that PHP rejects with the class of the same name: intdiv() and `%` raise it. It names its PHP class, so `catch (DivisionByZeroError $e)` matches it exactly and `catch (Error $e)` matches it on the name's suffix, as in PHP.
func (*DivisionByZeroError) Error ¶ added in v0.3.4
func (e *DivisionByZeroError) Error() string
Error renders the message PHP carries for the same operation.
func (*DivisionByZeroError) ThrowableClass ¶ added in v0.3.4
func (e *DivisionByZeroError) ThrowableClass() string
ThrowableClass names the PHP class, implementing Throwable.
type ExitError ¶
type ExitError struct {
Code int
}
ExitError is returned when PHP die()/exit() interrupts script execution.
func (*ExitError) ScriptExit ¶ added in v0.3.3
ScriptExit reports the status a script ended with, and marks this error as an ending rather than a failure.
It exists so a package that cannot name *ExitError can still recognise one: runner imports flatstack/engine, so engine cannot import runner back, and the VM has to know an exit when it unwinds one past a catch clause. Asking the error what it is keeps that seam an interface rather than a string comparison on the message.
type ExprCache ¶
type ExprCache struct {
// contains filtered or unexported fields
}
ExprCache stores immutable compiled expressions by AST node identity and flat bytecode by parsed program identity. Runtime-local binding metadata (compiledExpr) is rebuilt per runtime; both maps retain their key's node for the lifetime of the explicitly shared cache. Capacity is bounded to prevent memory leaks.
func NewExprCache ¶
func NewExprCache() *ExprCache
NewExprCache returns an empty compiled expression cache with default capacity (10,000 entries).
func NewExprCacheWithCapacity ¶ added in v0.2.1
NewExprCacheWithCapacity returns an empty expression cache bounded to maxEntries.
func (*ExprCache) Clear ¶ added in v0.2.1
func (c *ExprCache) Clear()
Clear resets the cached compiled expressions.
func (*ExprCache) EnsureFlat ¶ added in v0.5.0
EnsureFlat compiles p into the flat-program table when it is not there yet and reports the compile verdict. It is the write-through form of the check flatstack.Supports makes: a caller gating a run on the compiler pays one compile, and the run reads it back instead of repeating it.
func (*ExprCache) GetExpr ¶ added in v0.5.0
GetExpr returns the direct-compiled expression cached for e, if any.
type FileMode ¶ added in v0.3.1
type FileMode uint32
FileMode is a Unix file mode written the way chmod writes it, in octal, with or without the leading zero: 0644 and 644 are the same mode. It is octal whether or not it says so, because a mode is never anything else.
The zero value means "not configured", which is a caller's cue to use its own default rather than a mode of 0000.
func ParseFileMode ¶ added in v0.3.1
ParseFileMode reads an octal file mode. An empty value is the zero value.
func (FileMode) MarshalYAML ¶ added in v0.3.1
MarshalYAML writes the mode back as a quoted octal string, so a round trip through a configuration file cannot come back as a decimal number.
func (FileMode) Mode ¶ added in v0.3.1
Mode converts to the Go representation, where the three special bits live outside the permission bits rather than above them.
func (FileMode) String ¶ added in v0.3.1
String writes the mode back as four octal digits, the spelling a configuration file and chmod() both use.
func (*FileMode) UnmarshalYAML ¶ added in v0.3.1
UnmarshalYAML reads a mode from a configuration file, where it is written as octal, quoted or not.
type FilenameObserver ¶ added in v0.2.1
FilenameObserver optionally receives the entrypoint passed to LoadFile.
type FuncSite ¶ added in v0.5.0
FuncSite is where a user function was declared. It is what turns the second declaration of a name into a message worth reading: PHP's fatal error names the first site, and a script that ends up with two declarations of the same function usually got there by including a file twice, in which case the first site is the only thing that says which file.
type HostPanicError ¶ added in v0.2.0
HostPanicError converts a panic raised by a registered Go constructor, function, or method into the runtime error path. PHP try/catch can therefore handle it like an error returned by the same host callable.
func (*HostPanicError) Error ¶ added in v0.2.0
func (e *HostPanicError) Error() string
Error names the callable that panicked and what it panicked with.
type IncludeCache ¶
type IncludeCache struct {
// contains filtered or unexported fields
}
IncludeCache stores parsed include/require programs by cleaned filesystem path. Parsed programs are treated as immutable by Runtime.Run/exec: hoisting copies declarations into runtime maps, while statement execution only reads the AST, so cached *model.Program values can be shared safely by callers that do not mutate ASTs themselves. Cache size is bounded to prevent memory leaks.
func NewIncludeCache ¶
func NewIncludeCache() *IncludeCache
NewIncludeCache returns an empty parsed include cache with default capacity (10,000 entries).
func NewIncludeCacheWithCapacity ¶ added in v0.2.1
func NewIncludeCacheWithCapacity(maxEntries int) *IncludeCache
NewIncludeCacheWithCapacity returns an empty include cache bounded to maxEntries.
func (*IncludeCache) Account ¶ added in v0.6.0
func (c *IncludeCache) Account(bytes int64)
Account records the heap a precompile pass added to this cache.
func (*IncludeCache) Clear ¶ added in v0.2.1
func (c *IncludeCache) Clear()
Clear resets the cached entries.
func (*IncludeCache) Get ¶
func (c *IncludeCache) Get(path string) (*model.Program, bool)
Get returns the parsed program cached for path, if any.
func (*IncludeCache) Len ¶ added in v0.2.1
func (c *IncludeCache) Len() int
Len returns the number of currently cached programs.
func (*IncludeCache) Precompiled ¶ added in v0.6.0
func (c *IncludeCache) Precompiled() int64
Precompiled answers the heap the passes over this cache added.
type IncludeFunc ¶
IncludeFunc resolves an include/require path to a parsed program. Wiring this from the host keeps the runner free of file-system and parser dependencies.
type IncludeObserver ¶ added in v0.2.1
IncludeObserver optionally receives the number of files included so far.
type InfoField ¶ added in v0.6.0
InfoField is one row of a phpinfo() section, printed as `Name => Value`.
type InfoSection ¶ added in v0.6.0
InfoSection reports the rows a subsystem contributes to phpinfo(), or none when it has nothing to say. It runs at the moment phpinfo() is called, so a section reports what is there then rather than what was there at registration.
type LookupError ¶ added in v0.6.0
type LookupError struct {
// Symbol is the name the host asked for, as it spelled it.
Symbol string
// Candidates holds what the name matched when it matched too much. It is
// empty for every other reason, which is what separates "there is no such
// function" from "say which one".
Candidates []string
// Reason says what went wrong in the words the host needs.
Reason string
}
LookupError reports a symbol that resolved to nothing, to more than one declaration, or to a signature the requested Go type cannot express.
func (*LookupError) Error ¶ added in v0.6.0
func (e *LookupError) Error() string
Error names the symbol and the reason, and lists what the name matched when it matched too much, so a host is told which spelling to use.
type Observer ¶ added in v0.2.1
type Observer interface {
UpdateStatus(context.Context, telemetry.State)
Trace(context.Context, string, ...telemetry.Kind) *telemetry.Span
}
Observer receives lifecycle updates for a Runtime. Implementations must be safe for use by concurrent runtimes. A span is returned so the interpreter can measure the region it just reported; a nil span is valid and every method on it does nothing, which is what an observer with no trace in the context returns.
type Options ¶
type Options struct {
// RootFS is the filesystem used to load PHP entrypoints and includes.
RootFS fs.FS `yaml:"-"`
// Database resolves the named connections the Database and
// Database\Migrate bindings open. Nil leaves the choice to the binding,
// which falls back to the process environment. A virtual host sets its
// own, so that the connections a site can name are only the ones it
// configured.
Database model.DatabaseProvider `yaml:"-"`
// Mail resolves the named mail servers the Mail binding and mail()
// deliver through. Nil leaves the choice to the binding, which falls back
// to a provider holding no servers, so mail() refuses catchably naming
// what is missing. A virtual host sets its own, so the servers a site can
// name are only the ones it configured.
Mail model.MailProvider `yaml:"-"`
// Stdin is exposed to scripts as the STDIN stream. A nil reader produces an
// empty stream; CLI hosts should pass os.Stdin explicitly.
Stdin io.Reader `yaml:"-"`
// SAPI provides output for `php_sapi_name`.
SAPI string `yaml:"-"`
// WorkDir is the directory inside RootFS used as the script working directory.
// Empty means the RootFS root.
WorkDir string `yaml:"work_dir"`
// Include names a file included ahead of every entrypoint, for the
// functions and classes an application expects to be there whatever it is
// running: a composer autoloader, a bootstrap file. It is the `--include`
// flag, and a virtual host sets its own in the runner block of its
// phpscript.yml.
//
// It is included once per request, before the entrypoint the request
// resolved to, so the entrypoint and everything it includes see what it
// declared. A file that is not there is skipped rather than reported: the
// name says what to load when the application provides it, and one setting
// covers a server, a script run and a fixture run of the same tree.
Include string `yaml:"include"`
// Precompile moves parsing and bytecode compilation off the request and
// onto startup. A host walks its source tree through a Precompiler before
// it serves anything, and LoadFile reads an entrypoint back out of the
// include cache rather than parsing the file again, so every request after
// the first runs the AST the caches are already keyed by.
//
// Nothing is invalidated. An edited file is picked up by a reload or a
// restart, and what the tree parsed to is resident until then.
Precompile bool `yaml:"precompile"`
// WritablePaths optionally restricts filesystem writes. When empty, writes are
// left to normal OS/user permissions. Enforcement is done by filesystem shims.
WritablePaths []string `yaml:"writable_paths"`
// UploadMaxFilesize is the largest file part a request may carry, PHP's
// upload_max_filesize. A part over it is reported to the script as
// UPLOAD_ERR_INI_SIZE and is not stored. Zero is no limit.
UploadMaxFilesize Size `yaml:"upload_max_filesize"`
// PostMaxSize is the largest request body that is parsed at all, PHP's
// post_max_size. A body over it leaves both $_POST and $_FILES empty, as it
// does in PHP. Zero is no limit.
PostMaxSize Size `yaml:"post_max_size"`
// MaxInputVars is how many fields are decoded into $_GET, $_POST and
// $_COOKIE, PHP's max_input_vars. Zero is PHP's default of 1000; negative
// is no limit.
MaxInputVars int `yaml:"max_input_vars"`
// MaxInputNestingLevel is the deepest bracket chain a field name may have,
// PHP's max_input_nesting_level. A field past it is dropped whole. Zero is
// PHP's default of 64; negative is no limit.
//
// Both bound attacker-controlled input: `a[x][x]...` costs an array a level.
MaxInputNestingLevel int `yaml:"max_input_nesting_level"`
// UploadFileMode is the mode move_uploaded_file() gives a stored upload.
// Zero means DefaultUploadFileMode; a host that serves uploads to nobody
// but itself sets something tighter, 0600 or 0640.
UploadFileMode FileMode `yaml:"upload_file_mode"`
// Env is the environment scripts read with getenv(). Nil means the
// process environment, minus what ScriptEnvironment holds back. A host
// that configured an env of its own passes it here, and a virtual host
// always does.
Env []string `yaml:"-"`
// MemoryLimit is the memory one script may allocate, PHP's memory_limit.
// Zero is no limit.
MemoryLimit Size `yaml:"memory_limit"`
// TimeLimit is how long one script may run before it is stopped, in
// seconds, PHP's max_execution_time. Zero is no limit.
//
// NOT ENFORCED YET. The key is accepted and carried so a configuration
// written today keeps working when enforcement lands, rather than
// failing to parse.
TimeLimit int `yaml:"time_limit"`
// ConcurrencyLimit is how many scripts may execute at once. Zero is no
// limit. It has no equivalent in php.ini, where the SAPI owns it; here
// one process serves several sites and each gets its own share.
//
// NOT ENFORCED YET. See TimeLimit.
ConcurrencyLimit int `yaml:"concurrency_limit"`
}
Options configures a Runtime.
type Pool ¶ added in v0.6.0
type Pool struct {
// contains filtered or unexported fields
}
Pool runs PHP on a fixed set of forks, fed from one queue: the workers are the parallelism and the queue is the backpressure, so a run that finds every worker busy waits its turn rather than starting a runtime of its own.
Nothing here is a sync.Pool. The worker count is the contract, and sync.Pool drops entries on a collection.
func NewPool ¶ added in v0.6.0
NewPool forks rt into workers runtimes, each reading from a queue of depth queue, and starts them.
Zero workers is GOMAXPROCS, which is the parallelism the machine has for work that is all CPU, and is what a PHP handler doing no IO is; a host whose handlers wait on a database wants more. Zero queue is DefaultQueue.
output is called once per worker, for where that worker's runtime writes when nothing has been pushed over it. A host wanting a run's output to reach somewhere of its own pushes a writer inside the run; see Runtime.PushOutput.
func (*Pool) Close ¶ added in v0.6.0
func (p *Pool) Close()
Close stops the workers once the runs already queued have been answered.
func (*Pool) Submit ¶ added in v0.6.0
Submit runs fn on a worker and waits for it, and reports whether it ran.
It answers false when ctx ends first, which for a served request is the client leaving: a run still queued is dropped rather than started for nobody, and a run already started is left to notice the disconnect itself, because stopping one halfway is the handler's decision and connection_aborted is how it makes it.
It also answers false once the pool is closed.
type Precompiler ¶ added in v0.6.0
type Precompiler struct {
// Root is the application root the tree is walked from.
Root fs.FS
// Includes receives every file that parsed, keyed by its path below Root.
// That is the key Runtime.LoadFile and include/require both resolve to,
// because a path is cleaned against the root before it is read.
Includes *IncludeCache
// Exprs receives the flat bytecode of each parsed program. Nil parses
// without compiling: a host running the interpreter never reads bytecode,
// and holding it is resident memory for nothing.
Exprs *ExprCache
// Workers bounds how many files are parsed at once. Zero is GOMAXPROCS,
// which is the parallelism the machine has for work that is all CPU.
Workers int
}
Precompiler fills the caches a source tree serves from, before it serves anything. Every .php file below Root is parsed into Includes and compiled into Exprs, so the parse and the compile a request pays for today are paid once at startup instead. Nothing is invalidated afterwards: an edited file is picked up by a reload or a restart.
func (Precompiler) Run ¶ added in v0.6.0
func (p Precompiler) Run() int
Run parses and compiles the tree, and reports how many files it cached. The heap the pass added is recorded on the include cache, which is what opcache_get_status() answers with.
type RedeclareError ¶ added in v0.5.0
type RedeclareError struct {
// Name is the function as a script spells it.
Name string
// At is the declaration being refused.
At FuncSite
// Previous is where it was declared first, zero when the name belongs to
// a registered binding rather than to a declaration in PHP source.
Previous FuncSite
// Builtin reports which of the two cases this is.
Builtin bool
}
RedeclareError is a second declaration of a function name that is already taken. PHP treats it as a fatal error; this runtime has one error path, so it is raised as a catchable RuntimeException and reaches a Go host as an error from Run.
It is a type rather than a bare error because the two runtimes have to agree on it. A compile failure normally means the bytecode engine does not cover some form yet and the interpreter runs the program instead; this is not that. It is a verdict on the program, which the interpreter would reach too, so flatstack raises it rather than falling back to a second opinion.
func (*RedeclareError) Error ¶ added in v0.5.0
func (e *RedeclareError) Error() string
Error writes PHP's fatal-error text for the same condition, with one deliberate difference: the paths are the ones the script named, resolved against the root the shims are bound to, where PHP prints host paths. A runtime serving scripts out of an fs.FS has no host path to print.
A program a host assembled itself carries no file or spans, so the clauses that would name a location are left out rather than written empty.
func (*RedeclareError) GetCode ¶ added in v0.5.0
func (e *RedeclareError) GetCode() int
GetCode answers PHP's zero, since there is no error number to report.
func (*RedeclareError) GetMessage ¶ added in v0.5.0
func (e *RedeclareError) GetMessage() string
GetMessage and GetCode are what a script reads off the caught value.
func (*RedeclareError) ThrowableClass ¶ added in v0.5.0
func (e *RedeclareError) ThrowableClass() string
ThrowableClass names the class a catch clause filters on. Exception rather than a name of its own: PHP has no class for this at all, because there it is a compile-time fatal that no catch can reach, so there is no spelling to match and Exception is the clause a script writing one would write.
type Runtime ¶
type Runtime struct {
// Env is the environment visible to PHP for this Runtime. New snapshots the
// host environment so mutations remain local to a single request/runtime.
Env map[string]string
// contains filtered or unexported fields
}
Runtime executes parsed PHP statements and evaluates compiled expressions with registered functions, classes, constructors, and runtime state.
func NewFlatStack ¶ added in v0.2.0
NewFlatStack returns a Runtime that executes supported programs through the flat bytecode backend and atomically falls back to the interpreter otherwise. Most callers should use flatstack.New, which preserves runner's public API.
func (*Runtime) AccountRequest ¶ added in v0.3.3
AccountRequest folds the size of host-owned request-lifetime values into the baseline the memory walk starts from: the request Context, the parsed *http.Request, the response writer. It is called once per value at the point a request crosses into the runtime; the walk then adds live script values on top. It is an estimate of what the request costs before any PHP evaluates, not an audit of every host allocation.
func (*Runtime) AsCallable ¶ added in v0.6.0
AsCallable describes v as something a host can run on another runtime: a closure, a method bound to its receiver, an object with __invoke, a declared function by name, or Class::method. What it captured comes along and is shared by every runtime running it, so a callable must read what it captured and not write to it.
The two array spellings are refused here and accepted everywhere else, which docs/README.md records as a decision. A Go func is refused for a different reason: it is not a declaration, so there is nothing for another runtime to run, and a host holding one already holds the call.
func (*Runtime) Callable ¶ added in v0.3.0
Callable resolves a PHP `callable` value into the uniform func(...any) (any, error) signature the runtime invokes everywhere.
Every spelling php accepts resolves: a *Callable, a Go func, "function_name", "Class::method", array($object, "method") and array("Class", "method"). It answers the call rather than the value, which is what a binding taking a callable declares; AsCallable is the other direction.
The second return reports whether v was callable at all; callers turn that into PHP's "not a valid callback" error with their own function name.
func (*Runtime) ClassExists ¶ added in v0.1.0
ClassExists reports whether a PHP or host-backed class exists. If autoload is true, registered autoloaders are given a chance to define a missing class.
func (*Runtime) ClientContext ¶ added in v0.6.0
ClientContext answers the connection being served, which is the request inside a handler and the host's context outside one. A binding that should end when the client leaves waits on this; one that should end when the script does waits on Runtime.Context.
func (*Runtime) CompiledTree ¶ added in v0.6.0
CompiledTree reports what the parsed and compiled source tree costs this runtime: cached programs, compiled expressions, and the heap a precompile pass measured itself adding, which is zero until one runs.
None of it is charged against memory_limit. The tree is shared by every request and outlives all of them, and php draws the same line by keeping a compiled script under opcache.memory_consumption.
func (*Runtime) ConnectionAborted ¶ added in v0.6.0
ConnectionAborted reports that the client closed the connection: the request being answered inside a handler, and whatever started the script outside one.
func (*Runtime) Const ¶
Const returns a registered constant value and whether it is defined.
The magic constants are not among them, which is what defined("__FILE__") and constant("__FILE__") are held to: php compiles those names and neither function can see one.
func (*Runtime) Database ¶ added in v0.3.1
func (rt *Runtime) Database() model.DatabaseProvider
Database returns the provider named connections resolve through, or nil when the host configured none. The binding decides what nil falls back to.
func (*Runtime) DeclaredClasses ¶ added in v0.1.0
DeclaredClasses returns the names of PHP classes and host-backed constructor classes currently available to the runtime. PHP does not guarantee ordering; phpscript sorts the snapshot for deterministic diagnostics.
func (*Runtime) DeclaredPrograms ¶ added in v0.6.0
DeclaredPrograms answers the programs whose declarations this runtime holds, by the filename each was hoisted under. A host building its own forks replays them; Fork does it already.
func (*Runtime) DefinedConstants ¶ added in v0.1.0
DefinedConstants returns a stable snapshot of all runtime constants.
func (*Runtime) DefinedFunctions ¶ added in v0.1.0
DefinedFunctions returns stable snapshots of registered host/internal and PHP user-defined function names.
func (*Runtime) EnterRequest ¶ added in v0.6.0
EnterRequest records the connection of one request while it is answered, and returns the function that puts the previous one back.
It is for a host answering several requests on one runtime, which HTTP\Mux does. Everything a request can change is saved: the connection connection_aborted() reports, whether a disconnect ends it, and the limit, because php settles all three per request and there a request is a script.
func (*Runtime) Eval ¶
Eval compiles e to a closure chain, binds the referenced variables from scope by slot, and runs it.
func (*Runtime) Fork ¶ added in v0.6.0
Fork returns a runtime that can run the same symbols as this one, writing to w, and shares its parse and bytecode caches. It carries no part of an execution, which is what makes it safe on a goroutine of its own, and it installs the whole standard library, which is why a Pool forks per worker rather than per request. The file comment above is the arrangement.
func (*Runtime) FreezeStdlib ¶ added in v0.3.0
func (rt *Runtime) FreezeStdlib()
FreezeStdlib snapshots constants after host bindings are registered so ResetSession can drop script-defined constants without losing the stdlib.
func (*Runtime) FunctionExists ¶ added in v0.3.0
FunctionExists reports whether name resolves to a host shim or a PHP user-defined function, backing `function_exists`. Template engines guard their generated block functions with it, so an always-false answer would redeclare them on every include.
func (*Runtime) HasErrorHandler ¶ added in v0.6.0
HasErrorHandler reports whether a host installed one with OnError, for a binding deciding where a message with nowhere obvious to go should go.
func (*Runtime) IgnoreUserAbort ¶ added in v0.6.0
IgnoreUserAbort reports whether a disconnect is being ignored.
func (*Runtime) IncludeFile ¶ added in v0.3.0
IncludeFile evaluates path as PHP in a fresh scope, the same way an `include` statement would. Hosts that resolve classes outside the interpreter (the composer autoloader) use it to pull a declaration file into the runtime.
func (*Runtime) IncludePath ¶ added in v0.1.0
IncludePath returns the current SPL include path.
func (*Runtime) IncludedFiles ¶
IncludedFiles returns the cleaned dirFS filenames included by this runtime.
func (*Runtime) InterfaceExists ¶ added in v0.5.0
InterfaceExists reports whether an interface is declared. If autoload is true, registered autoloaders are given a chance to define a missing one; composer's autoloader maps interfaces and classes through the same PSR-4 table.
func (*Runtime) InvokeClosure ¶ added in v0.6.0
InvokeClosure runs a closure declaration on this runtime, in a scope holding its arguments and nothing else.
It is the re-entry a host callback needs. The declaration is AST, so it runs on whichever runtime the caller has; what it does not get is the scope the closure was written in, which is why Captures has to be false for the result to mean anything. A fresh statics bag per call is the other half of that: two goroutines running the same declaration are two calls, not one function accumulating.
func (*Runtime) InvokeNamed ¶ added in v0.6.0
InvokeNamed runs the PHP function name with args, on a clean stack holding nothing but the arguments.
It is the re-entry a host callback needs: a name is a program counter, and everything else about the call comes in through args. A closure is not callable this way - it carries the scope it was written in, which belongs to the runtime that built it - which is why a host that wants a callback on another goroutine asks for one by name.
func (*Runtime) Load ¶
Load parses PHP source into a program. The source names no file, so __FILE__ and __DIR__ stay names for the runtime to answer.
func (*Runtime) LoadFile ¶
LoadFile reads and parses a PHP file from the runtime source FS.
Options.Precompile makes the include cache answer for entrypoints as well as for includes: the file is parsed once for the life of the process, so the bytecode and the compiled expressions keyed by that AST are read back instead of built again per request. Without it the file is read and parsed every time, which is what a CLI run and an unconfigured host want.
func (*Runtime) LookupConstructor ¶ added in v0.3.0
LookupConstructor returns the host constructor registered for name.
func (*Runtime) LookupFunc ¶ added in v0.3.3
LookupFunc returns the host function registered for name. Introspection tooling uses it to reflect over a binding's Go signature; a PHP user-defined function resolves too, as whatever callable the runtime stored for it.
func (*Runtime) Mail ¶ added in v0.6.0
func (rt *Runtime) Mail() model.MailProvider
Mail returns the provider named mail servers resolve through, or nil when the host configured none. The binding decides what nil falls back to.
func (*Runtime) MemoryLimit ¶ added in v0.3.3
MemoryLimit returns the configured memory limit.
func (*Runtime) MemoryPeak ¶ added in v0.3.3
MemoryPeak returns the high-water usage mark. Peak is sampled at walk points (memory_get_usage calls and limit checkpoints), so an allocation both made and released between walks does not raise it, unlike PHP's allocator-level peak.
func (*Runtime) MemoryUsage ¶ added in v0.3.3
MemoryUsage returns the current request-scoped memory estimation in bytes, computed by a fresh walk of the live roots.
func (*Runtime) MemoryWalk ¶ added in v0.3.3
MemoryWalk recomputes live usage from the roots: the interpreter frame stack, globals, class statics, and any running flat VM's live values. A visited set keyed on container identity counts a value reachable through several variables once and terminates cycles. The result refreshes the cached usage and the peak.
func (*Runtime) MethodExists ¶ added in v0.3.0
MethodExists reports whether a declared PHP class has a method by that name, using PHP's case-insensitive method lookup. It answers only for interpreted classes; a host-backed one is reflected over by its caller.
func (*Runtime) Observe ¶ added in v0.2.1
Observe registers an observer and reports that this Runtime is starting.
func (*Runtime) OnError ¶
OnError installs an error handler (register_error_handler). When set, runtime evaluation errors are routed here instead of aborting the caller.
func (*Runtime) Output ¶ added in v0.3.0
Output returns the writer script output goes to: echo statements, inline HTML, and any builtin that emits text of its own, such as die() with a message, so their text joins the response body in the order the script produced it.
While a redirection is active (PushOutput, which output buffering is built on) this is the innermost writer, so everything the script emits is captured rather than sent on.
func (*Runtime) OutputDepth ¶ added in v0.3.0
OutputDepth reports how many redirections are active.
func (*Runtime) PHPInfo ¶ added in v0.1.0
PHPInfo prints a compact phpinfo-style text report for the phpscript runtime. It intentionally reports runtime facts rather than PHP extensions that phpscript does not provide.
func (*Runtime) PopOutput ¶ added in v0.3.0
PopOutput ends the innermost redirection, reporting whether one was active. Output resumes going to the enclosing writer, which is what makes nested captures compose.
func (*Runtime) Precompiled ¶ added in v0.6.0
Precompiled reports whether this runtime was configured to precompile.
func (*Runtime) PushOutput ¶ added in v0.3.0
PushOutput redirects script output to w until the matching PopOutput. Pushes nest: the innermost writer receives the output, so a captured region can itself capture.
func (*Runtime) RecordError ¶ added in v0.3.1
RecordError reports err on the trace of the request this runtime is serving, as the failure of the script it is running. Run calls it for the error a script ends with; a host calls it for a failure that happened outside the script, before or around it, which the script therefore has no throw to catch: a request body refused for its size, say.
It records and returns. It does not unwind PHP execution, so nothing about it is visible to a script through try/catch; a Go host observes it on the trace, or through the handler installed with OnError.
func (*Runtime) RegisterAutoloader ¶ added in v0.1.0
RegisterAutoloader appends or prepends a callback to the SPL autoload queue. The callback receives a fully-qualified class name without a leading slash.
func (*Runtime) RegisterClass ¶
RegisterClass adds a resolved class to the class table so `new Name` works.
func (*Runtime) RegisterConstructor ¶
RegisterConstructor binds a class name to a Go constructor so `new Name` in PHP instantiates a native Go value. The constructor may take a leading context.Context (auto-injected) and may return a trailing error, which is surfaced to the interpreter as a thrown error. When a direct variable assignment receives a constructed value that implements SetID(string), the runtime passes it the PHP variable name without the leading dollar sign. Example:
rt.RegisterConstructor("Storage", func(ctx context.Context) (Storage, error) { ... }).
// PHP: $storage = new Storage; // == storage, err := NewStorage(ctx).
func (*Runtime) RegisterFunc ¶
RegisterFunc forwards a Go function (or any callable) into the VM under name. This is the shim mechanism: e.g. rt.RegisterFunc("strlen", func(s string) int { return len(s) }) makes `strlen($x)` work in script expressions.
func (*Runtime) RegisterInclude ¶ added in v0.3.0
RegisterInclude installs a host implementation of one include target: an include or require of path runs fn instead of parsing the file, and the script sees fn's return value where PHP would see the file's.
This is for files the runtime reimplements in Go. composer's generated vendor/autoload.php is the motivating case: it bootstraps a class loader through PHP features the interpreter does not support, while phpscript can read the same composer metadata natively. Binding it here rather than installing the loader at startup keeps the PHP semantics intact: nothing is autoloadable until the script has actually included the autoloader.
func (*Runtime) RegisterInfo ¶ added in v0.6.0
func (rt *Runtime) RegisterInfo(name string, section InfoSection)
RegisterInfo adds a named section to phpinfo(), after the runtime's own block. Sections print in registration order, and one reporting no rows is left out entirely rather than printed as a heading over nothing.
It is how a binding answers for memory it holds across requests: a store bound into the context, a cache a precompile pass filled. None of that is in memory_get_usage(), which measures one script's live values, so phpinfo() is where the process-lifetime side is visible.
func (*Runtime) RegisterShutdown ¶ added in v0.2.1
RegisterShutdown appends a callback to run when the current program exits. Shutdown callbacks run in registration order, including after exit or error.
func (*Runtime) Reset ¶ added in v0.5.0
Reset returns the runtime to the state a new one is in, so a pool can hand the same value to the next program instead of building another.
It is ResetSession plus what outlives a session: the parse caches and the two maps keyed by AST node, which ResetSession keeps because a --count loop runs one program and the keys are the same nodes each time. Across two programs they hold the previous tree alive. The maps are cleared rather than replaced, so the next program starts on the buckets they grew.
func (*Runtime) ResetSession ¶ added in v0.3.0
ResetSession prepares the runtime to execute another program: new output and stdin, empty globals and user declarations. Host functions, constructors and the expression/bytecode caches stay.
func (*Runtime) ResolvePath ¶ added in v0.5.0
ResolvePath maps a path a script supplied onto the source filesystem, through the working directory. It is what an include resolves through, exported so a binding taking a path from PHP resolves it to the same file: a runtime where include "x.php" and file_get_contents("x.php") name different files would be worse than either rule on its own.
func (*Runtime) SPLAutoload ¶ added in v0.1.0
SPLAutoload implements PHP's default autoloader: lowercase the qualified class name and search each include_path entry for class.php.
func (*Runtime) SetConst ¶
SetConst registers a PHP constant (e.g. define("FOO", 1) or a built-in like T_VARIABLE). Constants are visible in every scope, including inside functions and methods, unlike globals, which PHP confines to the global scope.
func (*Runtime) SetContext ¶
SetContext installs the lifecycle context auto-injected into registered Go callables whose first parameter is a context.Context (constructors, methods, functions). Defaults to context.Background().
func (*Runtime) SetCoverage ¶ added in v0.4.0
SetCoverage installs a statement-coverage collector; nil turns collection off. Coverage is an interpreter feature: while a collector is installed, a runtime created with NewFlatStack stops delegating to the bytecode backend, because flatstack carries no coverage support (docs/flatstack.md) and the fallback is atomic — a program partly counted would be a program partly run.
func (*Runtime) SetExprCache ¶
SetExprCache installs a source-keyed compiled-program cache that is safe to share across runtimes. AST-specific expression metadata remains runtime-local. Passing nil disables cross-runtime expression caching.
func (*Runtime) SetGlobal ¶
SetGlobal seeds a variable into the global scope before execution. Useful for injecting request data (the README's $_SERVER gray area) or, in tests, an input value.
func (*Runtime) SetIgnoreUserAbort ¶ added in v0.6.0
SetIgnoreUserAbort decides whether the client going away ends the script.
Off, which is the default, the disconnect stops the script where it next looks. On, the script runs to its own end and asks ConnectionAborted when it wants to know. A time limit still applies either way: ignoring the client is not permission to run forever.
func (*Runtime) SetIncludeCache ¶
func (rt *Runtime) SetIncludeCache(cache *IncludeCache)
SetIncludeCache installs a shared include cache. A cache must only be shared by runtimes whose include paths resolve within the same source-root namespace. Passing nil disables include caching.
func (*Runtime) SetIncludePath ¶ added in v0.1.0
SetIncludePath sets the path list used by the default SPL autoloader and returns its previous value.
func (*Runtime) SetIncludeResolver ¶
func (rt *Runtime) SetIncludeResolver(fn IncludeFunc)
SetIncludeResolver installs the include/require resolver.
func (*Runtime) SetPreparer ¶ added in v0.6.0
SetPreparer records how a host installs this runtime's bindings, so that Fork can install the same ones on a child.
stdlib.Register calls it. A host registering its own bindings on top passes a function that installs those too, or its forks will not have them.
func (*Runtime) SetTimeLimit ¶ added in v0.6.0
SetTimeLimit bounds how long the script may run, restarting the clock from now the way a second set_time_limit call does. Zero removes the limit, and a limit past maxTimeLimit is held there.
It is the runtime's limit wherever it is called from, including a handler of the script's own HTTP server: a serving script is one script and this is its deadline. The context every binding holds is cancelled with it, so a blocked Go call ends too, and a handler extending the limit extends the server rather than replacing the context the server is parked on.
func (*Runtime) SetWorkDir ¶ added in v0.5.0
SetWorkDir moves the working directory and reports whether it could. A relative path resolves against the current one and an absolute path against the source root, and neither climbs out of it.
The directory is per-runtime state, so a script moving it moves nothing another request sees and os.Chdir is never called. A path naming no directory is refused, which is what php's false return means.
func (*Runtime) Stdin ¶ added in v0.2.0
Stdin returns the input stream configured by the runtime host.
func (*Runtime) Trace ¶ added in v0.2.1
Trace publishes a trace span to registered observers and returns the first mutable span provided by one of them.
func (*Runtime) UnregisterAutoloader ¶ added in v0.3.0
UnregisterAutoloader removes a callback from the SPL autoload queue, matching it the way PHP does: by the function, object and method it names rather than by identity, since each `array($this, "loadClass")` is a fresh array.
func (*Runtime) UpdateFilename ¶ added in v0.2.1
UpdateFilename publishes the PHP entrypoint to observers that support filename updates.
func (*Runtime) UpdateIncludedFiles ¶ added in v0.2.1
UpdateIncludedFiles publishes the current number of included files.
func (*Runtime) UpdateStatus ¶ added in v0.2.1
UpdateStatus publishes a lifecycle phase to all registered observers. It is also available to hosts for phases that occur outside PHP execution.
func (*Runtime) UploadFileMode ¶ added in v0.3.1
UploadFileMode returns the mode move_uploaded_file() gives a stored upload, which is DefaultUploadFileMode unless the host configured one.
func (*Runtime) WorkDir ¶
WorkDir returns the working directory as an fs.FS path inside the source root: "." for the root itself, "app" for a directory below it. Bindings that resolve a path against it want this spelling.
func (*Runtime) WorkDirPath ¶ added in v0.5.0
WorkDirPath returns the working directory the way a script reads it, written from the source filesystem's root. This is what getcwd() answers with.
func (*Runtime) WritablePaths ¶
WritablePaths returns the configured writable path whitelist.
type RuntimeException ¶ added in v0.3.3
RuntimeException represents a PHP RuntimeException raised by the runner.
func NewRuntimeException ¶ added in v0.3.3
func NewRuntimeException(message string, code int) *RuntimeException
NewRuntimeException creates a new RuntimeException instance.
func (*RuntimeException) Error ¶ added in v0.3.3
func (e *RuntimeException) Error() string
Error is the message, which is what a Go caller reads.
func (*RuntimeException) GetCode ¶ added in v0.3.3
func (e *RuntimeException) GetCode() int
GetCode is the code under the name a script calls it by.
func (*RuntimeException) GetMessage ¶ added in v0.3.3
func (e *RuntimeException) GetMessage() string
GetMessage is the message under the name a script calls it by.
func (*RuntimeException) ThrowableClass ¶ added in v0.3.4
func (e *RuntimeException) ThrowableClass() string
ThrowableClass names the PHP class, implementing Throwable, so a catch filters on it the way it filters on one a script constructed.
type Scope ¶
type Scope struct {
// contains filtered or unexported fields
}
Scope is a flat variable table for one execution frame.
PHP has no block scoping: variables introduced inside if/for/foreach bodies live in the enclosing function scope. Each function call gets a fresh Scope; the file body runs in the global Scope.
There is intentionally no `global` keyword implemented.
func ScopeFromContext ¶ added in v0.0.6
ScopeFromContext returns the active PHP execution frame attached to a context auto-injected into a registered free function.
func (*Scope) Defer ¶ added in v0.1.3
Defer registers a callback to run when the current PHP execution frame returns. Callbacks run in last-in, first-out order.
func (*Scope) DefinedVars ¶ added in v0.1.0
DefinedVars returns a snapshot of PHP-visible variables in this frame. Interpreter bookkeeping slots use a double-underscore prefix and are not PHP variables, so they are omitted. `this` goes with them: it is bound by the call rather than declared in the body, and php leaves it out of get_defined_vars() for that reason.
type Size ¶ added in v0.3.1
type Size int64
Size is a byte count written the way a php.ini size is: a bare number of bytes, or a number with an M suffix for megabytes. PHP's K and G shorthands are rejected rather than guessed at, so a configuration file says what it means in one of two spellings and nothing else parses.
The zero value means no limit, which is what 0 means in php.ini.
func (Size) Bytes ¶ added in v0.3.1
Bytes returns the limit as a byte count. Zero is no limit; a caller has to decide what that means for it.
func (Size) Exceeds ¶ added in v0.3.1
Exceeds reports whether n is over the limit. A zero Size is no limit, so nothing exceeds it.
func (Size) MarshalYAML ¶ added in v0.3.1
MarshalYAML writes the size back as a string, so a round trip through a configuration file keeps the M suffix.
func (Size) String ¶ added in v0.3.1
String writes the size back in the spelling it was read in: megabytes when it is a whole number of them, bytes otherwise.
func (*Size) UnmarshalYAML ¶ added in v0.3.1
UnmarshalYAML reads a size from a configuration file, where it is written either as a bare number or as a quoted or unquoted "8M".
type Throwable ¶ added in v0.3.4
type Throwable interface {
error
// ThrowableClass returns the PHP class name, such as "InvalidArgumentException".
ThrowableClass() string
}
Throwable is implemented by a value that knows which PHP class it was constructed as.
The class is asked for rather than read off the Go type, because every SPL name is one Go type: reflection would answer "Exception" for an InvalidArgumentException. It is also the predicate that separates a PHP throwable from an error a Go binding returned, which a Go type name cannot do; a driver type called Error would otherwise be read as PHP's Error class and fall out of the `catch (Exception $e)` a script wrote around its query.
type TimeLimitError ¶ added in v0.6.0
type TimeLimitError struct {
// Limit is the limit that was set, zero when the client went away first.
Limit time.Duration
// Aborted reports that the client closed the connection.
Aborted bool
}
TimeLimitError ends a script that ran past set_time_limit, or whose client went away while it was not ignoring that.
A host distinguishes the two causes through Aborted, because they call for different answers: a timeout is the site's problem and a disconnect is not.
func (*TimeLimitError) Error ¶ added in v0.6.0
func (e *TimeLimitError) Error() string
Error says which of the two deadlines ended the script, because the client leaving and the clock running out read the same to everything downstream.
type TypeError ¶ added in v0.3.3
TypeError reports an argument that cannot be converted to the type the callable's parameter declares. PHP raises TypeError for the same call, so it names that class: `catch (TypeError $e)` and `catch (Error $e)` match it and `catch (Exception $e)` does not, as in PHP.
func (*TypeError) Error ¶ added in v0.3.3
Error renders the message PHP's TypeError carries for the same call.
func (*TypeError) ThrowableClass ¶ added in v0.3.4
ThrowableClass names the PHP class, implementing Throwable.
type UndefinedConstantError ¶ added in v0.4.0
type UndefinedConstantError struct {
Name string
}
UndefinedConstantError reports a bare name no constant, no scope value and no superglobal defines.
PHP 8 raises Error for the same expression. This raises RuntimeException, a deliberate break: an Error in PHP is a fault in the program that a caller is not expected to handle, and a name this runtime does not define is an ordinary condition a script can catch and answer for, the same way exceeding memory_limit is. It also puts the condition where `catch (Exception $e)` already looks, which is the clause a script has written.
func (*UndefinedConstantError) Error ¶ added in v0.4.0
func (e *UndefinedConstantError) Error() string
Error names the constant, quoted the way php quotes it.
func (*UndefinedConstantError) ThrowableClass ¶ added in v0.4.0
func (e *UndefinedConstantError) ThrowableClass() string
ThrowableClass names the PHP class, implementing Throwable. RuntimeException does not end in Error, so `catch (Exception $e)` takes it and `catch (Error $e)` does not.
type UploadedFile ¶ added in v0.3.1
type UploadedFile struct {
Name string // client-supplied file name, without any directory part
// FullPath is the file name as the client sent it, directory part and all,
// which a directory upload uses to say where in the tree a file sat. PHP
// 8.1 added it; like Name, it is the client's word and not a path on this
// host.
FullPath string
Type string // client-supplied content type
TmpName string // path of the temporary copy, empty when Error is set
Size int64
Error int // an UPLOAD_ERR_* code, UploadErrOK when the part was stored
}
UploadedFile is one file part of a multipart request body, in the shape a PHP $_FILES entry exposes. TmpName is the absolute path of the server-side copy, which lives until Cleanup runs or the script moves it away.
Source Files
¶
- arithmetic_error.go
- bindings.go
- callable.go
- convert.go
- deadline.go
- dispatch.go
- expr_cache.go
- filemode.go
- flatstack.go
- fork.go
- helpers.go
- ident.go
- include_cache.go
- info.go
- instanceof.go
- lookup.go
- memory.go
- object_error.go
- options.go
- output.go
- precompiler.go
- redeclare.go
- request.go
- response.go
- runner.go
- runtime.go
- scope.go
- size.go
- static.go
- throwable.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package coverage is the statement-coverage extension of the runner: a collector the interpreter reports statement executions to, and the profile blocks a host renders from it.
|
Package coverage is the statement-coverage extension of the runner: a collector the interpreter reports statement executions to, and the profile blocks a host renders from it. |
|
Package expr is the runner's expression engine: model.Expr compiles to a chain of typed Go closures (direct.go) that call the PHP-semantic helpers directly and read variables by slot from the Env carrier.
|
Package expr is the runner's expression engine: model.Expr compiles to a chain of typed Go closures (direct.go) that call the PHP-semantic helpers directly and read variables by slot from the Env carrier. |
|
Package mapmap holds a read-only map with a request-scoped layer of edits over it.
|
Package mapmap holds a read-only map with a request-scoped layer of edits over it. |