Skip to content
Greg Bowler edited this page May 18, 2026 · 3 revisions

Page logic is the PHP entry point for a page request. Its job is to respond to the request, coordinate the application code that does the real work, and prepare the final page response.

That makes it a good place for orchestration, but not a good place for large business rules. Complex tasks and heavy lifting should be done in application classes instead.

How logic pairs with a view

Like page views, page logic files are discovered from the URI. A request to /about can use:

  • page/about.html for the page view
  • page/about.php for the page logic

If there is no logic file, the page is simply static. That is completely valid and is often the right place to start.

Logic hooks

go functions

To execute PHP when a request is made, the go function is the standard entry point for a page. It gets executed automatically during a normal request, after WebEngine has prepared the request, response, service container, and view model.

In go, we usually read input, call application classes, and bind the results into the page.

An example page logic, that simply changes the title of the page, looks like this:

use GT\Dom\HTMLDocument;

function go(HTMLDocument $document):void {
	$document->title = "Title changed from PHP!";
}

The parameters of go functions are dynamically injected at runtime. This means you can request any object as a go parameter, and WebEngine will provide you with a matching instance from its service container.

Here's a more complex page logic that takes the user input, binds a value to the document, or redirects if the value is not set:

use GT\DomTemplate\Binder;
use GT\Input\Input;
use GT\Http\Response;
use App\Invoice\InvoiceRepository;

function go(Binder $binder, Input $input, Response $response, InvoiceRepository $invoiceRepository):void {
	$invoiceCode = $input->getString("invoice");
	$invoice = $invoiceRepository->getById($invoiceCode)
	
	if(!$invoice) {
		$response->redirect("?no-invoice");
	}
	
	$binder->bindKeyValue("total", $invoice->calculateTotal());
}

Logic functions should not output anything directly. If an echo or var_dump is made from page logic, WebEngine captures that output and sends it to the browser's developer console.

do functions

do functions are for named user actions. When a request includes a do value, WebEngine looks for a matching do_* function and runs it.

For example, if a form submits do=save-profile, WebEngine will look for:

function do_save_profile():void {
	// ...
}

do functions behave in the same way as go functions, and share the same service container, so the parameters can define the scope of what each function has access to.

Order of execution

If present, the hooks run in this order:

  1. go_before
  2. matching do_*
  3. go
  4. go_after

When logic is assembled from multiple matching files, the ordering follows the router's assembly rules so the broader shared logic and the more specific page logic run in a predictable sequence. In practice, this means we can use shared logic without losing the obvious page-specific entry point.

To avoid any doubt, WebEngine emits an X-Logic-Execution header containing a list of all logic functions that were executed on the request, in order of execution. This header is not sent when in production mode.

What to do in page logic

Page logic is a good place to:

What NOT to do in page logic

Avoid putting large business rules in the page file. Avoid raw SQL manipulation code. Avoid building HTML in strings. Avoid relying on echo for normal output.

Page logic works best when it's easy to scan, and should work like a newspaper: the developer should be able to read the headlines, and click through to the application classes when they need more detail. A good page file should make the request flow obvious at a glance.


Now the pages can have dynamic content, let's learn about dynamic URLs.

Clone this wiki locally