Development

How to Review AI-Generated PHP Code Without Fooling Yourself

Learning how to review AI-generated PHP code is becoming more important than learning how to generate it.

Producing code is easy. A model can return a convincing class, REST endpoint, migration, or test suite in seconds. The dangerous part is that polished code lowers our skepticism before it earns our trust.

Syntax highlighting does not prove the requirements were understood. Type declarations do not prove the data model is correct. A passing unit test does not prove the test covered the real failure mode.

The reviewer still owns the result.

How should you review AI-generated PHP code?

Quick answer: Review the assumptions before the implementation. Then verify authorization, validation, data access, compatibility, error handling, and tests against the real system. Treat AI output as an untrusted patch from a fast contributor who has never operated your product.

That framing is useful because it separates speed from authority. The model can propose. It cannot accept production risk for you.

Start with the problem, not the diff

The first review question should not be "Does this code look clean?"

Ask:

  • What user or system behavior is supposed to change?
  • What must remain unchanged?
  • Which source defines the requirement?
  • What data enters the feature?
  • What side effects can occur?
  • What failure would hurt customers most?

AI tools often fill missing context with plausible assumptions. That can produce beautiful code for the wrong problem.

Before reading line by line, write down the acceptance criteria in plain language. If the patch cannot be mapped to those criteria, stop. Reviewing implementation details before resolving the behavior only makes the wrong solution feel familiar.

Review every hidden assumption

AI-generated PHP frequently assumes things such as:

  • A database column always exists.
  • A WordPress hook runs only once.
  • A function returns a value instead of WP_Error.
  • A current user is present in cron or CLI contexts.
  • An array key exists because the happy-path example contained it.
  • A remote API responds with valid JSON and a successful status.
  • A plugin dependency is active and on the expected version.
  • A request cannot be repeated.

Turn each assumption into one of three things:

  1. A validation check
  2. A documented precondition
  3. A test

If it becomes none of them, it is still an unowned risk.

Verify WordPress authorization separately from input security

This is one of the most common places where generated WordPress code looks safer than it is.

These controls solve different problems:

  • Capability checks determine whether the current user may perform the action.
  • Nonces help verify request intent and protect against cross-site request forgery.
  • Sanitization converts incoming data into an expected form.
  • Validation decides whether that data is acceptable.
  • Escaping makes output safe for a particular HTML, attribute, URL, or JavaScript context.

A nonce is not permission. sanitize_text_field() is not validation. Escaping data before storing it is not a replacement for escaping at output. The WordPress security handbook documents these as separate controls and recommends validating and sanitizing input, then escaping output as late as practical.

For every entry point, trace the full chain:

  1. Who can reach it?
  2. Which capability is required?
  3. How is request intent verified?
  4. How is each field sanitized and validated?
  5. Where is the data stored or sent?
  6. How is it escaped when rendered?

Check REST routes, AJAX handlers, form posts, WP-CLI commands, cron callbacks, webhooks, and background jobs independently. Copying the same security pattern into each context can be wrong because each context has different authentication and request behavior.

Inspect data access for correctness and scale

Generated code commonly produces a database query that is locally correct and operationally expensive.

Look for:

  • Queries inside loops
  • Unbounded result sets
  • Missing indexes for new filters or joins
  • Counting by loading every row
  • Incorrect assumptions about $wpdb->prepare() placeholders
  • Raw table names without the proper prefix
  • Writes without transactions where partial state matters
  • Repeated metadata queries that should be cached or batched
  • Cache keys missing a tenant, user, language, or permission dimension

Ask what happens with ten records, ten thousand records, and ten concurrent requests.

An AI assistant cannot know the production distribution unless you provide it. If it saw a fixture with three membership levels, it may choose an approach that collapses when a large site has years of order and activity data.

Use query logs and profiling tools. Performance review based only on visual inspection is guesswork.

Check WordPress lifecycle assumptions

WordPress behavior depends heavily on when code runs.

A function may work but be attached to the wrong hook. A class may initialize before its dependency. A translation may load too late. A rewrite rule may flush on every request. A scheduled event may be registered repeatedly.

For generated WordPress code, verify:

  • Activation and deactivation behavior
  • Hook priority and accepted arguments
  • Admin, frontend, REST, cron, and CLI contexts
  • Multisite and network activation where supported
  • Object-cache behavior
  • Request idempotency
  • Dependency availability
  • Upgrade routines for existing installations

The code itself rarely contains enough evidence. Read the caller, the hooks around it, and the data written by previous versions.

Verify the declared PHP and WordPress compatibility

Models tend to generate modern syntax because modern examples are cleaner. Your product may support older runtimes.

Check for:

  • Constructor property promotion
  • Enums
  • Readonly properties and classes
  • Intersection or disjunctive normal form types
  • New functions unavailable on the minimum PHP version
  • WordPress functions or hooks introduced after the supported Core version
  • Dependency versions that require a newer runtime

Do not rely on memory. Run the code on the oldest supported PHP and WordPress combination, then run it on the newest combination.

Compatibility belongs in automated tests because humans are poor at spotting every version boundary during review.

Make error handling prove what failed

AI-generated code often wraps a large block in try and returns a generic message. That prevents a visible crash but can destroy diagnostic value.

Good error handling should answer:

  • Which operation failed?
  • Which input or entity was involved?
  • Is retrying safe?
  • Was any partial state written?
  • What should the user see?
  • What should the operator log?
  • Does the log expose private information?

Watch for retries around non-idempotent operations. Retrying a read is different from retrying a charge, email, membership grant, or webhook acknowledgment.

An error path deserves the same design attention as the happy path. In production, it often receives more traffic than anyone expected.

Review the tests as skeptically as the code

AI can generate a test that passes because it repeats the implementation's assumptions.

Common weak patterns include:

  • Mocking the method that contains the bug
  • Asserting only that no exception occurred
  • Testing one valid input and no invalid inputs
  • Reproducing generated output as the expected value
  • Ignoring permissions and user roles
  • Avoiding the database, filesystem, or HTTP boundary that matters
  • Calling private methods instead of exercising public behavior

Require tests for behavior, boundaries, and regressions.

At minimum, cover:

  • The normal case
  • Empty and malformed input
  • Unauthorized access
  • Dependency failure
  • Repeated execution
  • The original bug or requirement
  • Existing behavior that must not change

For critical plugin flows, integration tests usually provide more confidence than a large collection of isolated mocks.

Look for fake abstractions and unnecessary code

AI tends to produce complete-looking architectures. A small requirement can emerge with factories, repositories, service containers, interfaces, value objects, custom exceptions, and configuration layers.

Each abstraction may be defensible by itself. Together they can make the code harder to understand than the problem.

Ask of every class and interface:

  • Does it isolate a genuine responsibility?
  • Does it remove duplication?
  • Does it protect a domain rule?
  • Does it make testing a meaningful boundary easier?
  • Is there more than one real implementation?

If the answer is no, deleting it may improve the patch.

Senior review is not the art of accepting sophisticated code. It is the discipline of keeping only the complexity the product needs.

Use tools to challenge the output

Manual review is necessary, but it should not work alone.

For PHP and WordPress code, I would use:

  • The project's test suite
  • PHPStan or Psalm
  • PHPCS with the project's standards
  • WordPress Plugin Check where applicable
  • Dependency and vulnerability scanning
  • Query Monitor or equivalent profiling
  • Tests against the minimum and maximum supported runtimes
  • A focused search for every changed function's callers

Static analysis catches inconsistent types and impossible branches. Coding standards expose suspicious patterns. Profiling reveals database and HTTP costs. None proves product correctness, but each tests a different claim the generated code is making.

My reusable AI-generated PHP review checklist

Requirements

  • Does the patch solve the stated behavior?
  • Are non-goals and unchanged behavior clear?
  • Were invented assumptions identified?

Security

  • Are capability checks correct for each entry point?
  • Are nonces used only for request intent, not authorization?
  • Are inputs sanitized and validated?
  • Is output escaped for its exact context?
  • Are secrets and private data protected?

Data and performance

  • Are queries bounded, indexed, and outside avoidable loops?
  • Are writes atomic enough for the business rule?
  • Are caching and invalidation correct?
  • Has realistic data volume been profiled?

Compatibility

  • Does syntax match the minimum PHP version?
  • Do APIs match the minimum WordPress version?
  • Are multisite, cron, CLI, and background contexts handled where promised?

Reliability

  • Are timeouts, remote errors, and partial failures handled?
  • Is repeated execution safe?
  • Do logs contain enough context without leaking data?

Design

  • Is each function or class focused on one responsibility?
  • Is shared logic reused instead of duplicated?
  • Can unnecessary abstraction be removed?

Tests

  • Does a test fail without the required change?
  • Are permissions, invalid input, and failure paths covered?
  • Do integration tests cross the boundaries that matter?

If a patch cannot survive this checklist, generation speed is irrelevant.

Frequently Asked Questions

Is AI-generated PHP code safe to use?

It can be used safely only after review and testing appropriate to its risk. Treat the output as untrusted code until its assumptions, security, compatibility, and behavior have been verified.

What is the biggest risk in AI-generated WordPress code?

The biggest risk is plausible code built on missing context. Authorization mistakes, incorrect lifecycle assumptions, and unbounded data access are common examples with real production impact.

Should every line of AI-generated code be manually reviewed?

Every production change should be understood by the responsible team. Mechanical output can be assisted by tests and analysis tools, but generated code should not bypass normal review because it arrived quickly.

Can automated tests replace code review?

No. Tests show that selected scenarios behave as expected. Review checks whether the right scenarios, requirements, security boundaries, and design were chosen.

Who is responsible when AI-generated code fails?

The people and organization that approve and deploy it remain responsible. The model cannot own an incident, explain a business decision, or repair customer trust.

Use AI for speed, then earn confidence

AI can shorten the distance from an idea to a candidate implementation. That is useful. It does not shorten the distance from candidate code to justified production confidence.

The more convincing the output looks, the more disciplined the review should become. Verify the problem, expose the assumptions, test the boundaries, measure the system, and remove unnecessary complexity.

The goal is not to prove the AI wrong. The goal is to make the software right.

For the broader workflow I use around planning, generation, and human judgment, read A Practical AI Workflow for WordPress Developers and Vibe Coding an Internal PHP App: What I Learned.