VOOZH about

URL: https://deepwiki.com/hypervel/api-client/8.3-magic-method-delegation

⇱ Magic Method Delegation | hypervel/api-client | DeepWiki


Loading...
Menu

Magic Method Delegation

Purpose and Scope

This document explains how magic method delegation is implemented in the hypervel/api-client package using PHP's __call() magic method. The package uses delegation in two key locations to provide seamless, fluent interfaces: ApiClient delegates to PendingRequest, and ApiResource delegates to ApiResponse.

For information about the fluent interface patterns that this delegation enables, see Fluent Interface Patterns. For information about the core classes involved, see ApiClient, PendingRequest, and ApiResource.


Overview

Magic method delegation is a PHP technique that uses the __call() magic method to forward method calls from one object to another. This pattern allows classes to act as facades or proxies, exposing the interface of a delegate object without explicit method definitions.

The package implements delegation in two strategic locations:

DelegatorDelegatePurpose
ApiClientPendingRequestProvides a fluent API entry point while maintaining separation between configuration and request execution
ApiResourceApiResponseExposes response methods directly on the resource while maintaining encapsulation

ApiClient to PendingRequest Delegation

Implementation

The ApiClient class uses the __call() magic method to delegate all undefined method calls to a fresh PendingRequest instance.

ApiClient::__call() → getClient() → new PendingRequest($this) → method(...$parameters)

Implementation Details:

src/ApiClient.php41-45 implements the delegation:


The delegation process:

  1. When a method is called on ApiClient that doesn't exist (e.g., get(), post())
  2. PHP invokes __call() with the method name and parameters
  3. getClient() creates a new PendingRequest instance at src/ApiClient.php112-115
  4. The method call is forwarded to the PendingRequest instance
  5. The result is returned directly to the caller

PHPDoc Type Hints

To provide IDE autocomplete and static analysis support, ApiClient uses the @mixin annotation at src/ApiClient.php12:


This annotation tells static analyzers that ApiClient behaves as if it implements all public methods from PendingRequest, enabling:

  • IDE autocomplete for methods like get(), post(), withHeaders(), etc.
  • Static type checking on method parameters and return values
  • Documentation generation tools to include delegated methods

Delegation Flow Diagram


Sources: src/ApiClient.php41-115

Benefits of This Pattern

BenefitDescription
Clean API SurfaceConsumers interact with ApiClient as the entry point without needing to know about PendingRequest
Separation of ConcernsApiClient handles configuration; PendingRequest handles request building and execution
Fresh StateEach method call gets a new PendingRequest instance, preventing state leakage between requests
Fluent ChainingSupports patterns like $client->withHeaders(...)->get(...) transparently

Code Entity Mapping

The delegation enables these method calls on ApiClient:


Sources: src/ApiClient.php12-115


ApiResource to ApiResponse Delegation

Implementation

The ApiResource class delegates method calls to its underlying ApiResponse instance, but with explicit method existence checking.

Implementation Details:

src/ApiResource.php63-72 implements the delegation with validation:


The delegation process:

  1. Method called on ApiResource that doesn't exist (e.g., status(), headers())
  2. __call() validates the method exists on ApiResponse at src/ApiResource.php65
  3. If valid, uses forwardCallTo() from the ForwardsCalls trait at src/ApiResource.php71
  4. If invalid, throws BadMethodCallException with a descriptive error at src/ApiResource.php66-68

ForwardsCalls Trait

ApiResource uses Hyperf's ForwardsCalls trait at src/ApiResource.php20 to handle the actual forwarding. This trait provides:

  • Exception context preservation
  • Proper error handling for undefined methods
  • Consistent behavior with framework conventions

PHPDoc Type Hints

The @mixin annotation at src/ApiResource.php16 provides type information:


This tells static analyzers that ApiResource exposes all public methods from ApiResponse.

Delegation Flow Diagram


Sources: src/ApiResource.php16-72

Differences from ApiClient Delegation

AspectApiClientApiResource
ValidationNo validation; all calls forwardedValidates method exists before forwarding
Error HandlingRelies on PendingRequest errorsThrows explicit BadMethodCallException
Instance CreationCreates new instance each callUses existing instance from constructor
Forwarding MechanismDirect property access (->{$method})Uses ForwardsCalls trait

Code Entity Mapping

The delegation enables these method calls on ApiResource:


Sources: src/ApiResource.php16-72


Delegation Architecture Comparison

Side-by-Side Implementation

FeatureApiClient DelegationApiResource Delegation
Magic Method__call()__call()
Target ObjectNew PendingRequest instanceExisting ApiResponse property
ValidationNone (implicit via PHP)Explicit method_exists() check
Error TypePHP's default undefined method errorBadMethodCallException
Type Hint@mixin PendingRequest<TResource>@mixin ApiResponse
Helper TraitNoneForwardsCalls

Unified Delegation Pattern


Sources: src/ApiClient.php41-115 src/ApiResource.php63-72


Common Delegated Methods

ApiClient → PendingRequest

These methods are commonly accessed via delegation:

Method CategoryMethods
HTTP Verbsget(), post(), put(), patch(), delete(), head(), send()
HeaderswithHeaders(), withHeader(), withToken(), withBasicAuth(), withUserAgent(), accept(), acceptJson(), contentType()
BodyasJson(), asForm(), withBody(), withData()
QuerywithQueryParameters()
ConfigurationwithResource(), withMiddleware(), disableMiddleware(), withOptions(), timeout()

ApiResource → ApiResponse

These methods are commonly accessed via delegation:

Method CategoryMethods
Status Checksstatus(), successful(), ok(), redirect(), failed(), clientError(), serverError()
Headersheader(), headers(), hasHeader()
Body Accessbody(), json(), object(), collect()
PSR-7getStatusCode(), getReasonPhrase(), getProtocolVersion()

Benefits and Trade-offs

Benefits

  1. Simplified API Surface: Consumers don't need to understand internal object hierarchy
  2. Type Safety: @mixin annotations provide IDE support and static analysis
  3. Encapsulation: Internal implementation details remain hidden
  4. Flexibility: Delegate object can be changed without affecting consumer code
  5. Fluent Interfaces: Enables method chaining across object boundaries

Trade-offs

  1. Runtime Performance: Small overhead from magic method invocation
  2. Debugging Complexity: Stack traces include additional delegation layer
  3. IDE Limitations: Some IDEs may not fully support @mixin annotations
  4. Implicit Contracts: Delegated interface is not enforced at compile time

When Delegation is Appropriate

Use CaseAppropriate?Reason
Facade pattern✅ YesSimplifies complex subsystem (ApiClient → PendingRequest)
Data wrapper✅ YesExposes underlying data methods (ApiResource → ApiResponse)
Deep hierarchies❌ NoCreates debugging complexity
Performance-critical paths⚠️ CautionMinor overhead may accumulate
Public APIs✅ YesProvides clean, stable interface

Implementation Best Practices

Based on the codebase's implementation:

1. Always Provide @mixin Documentation


This ensures IDE support and documents the delegation contract.

2. Validate When Necessary

ApiResource validates method existence before delegation to provide better error messages:


3. Use Framework Utilities

The ForwardsCalls trait at src/ApiResource.php20 provides consistent forwarding behavior with the framework.

4. Consider Instance Lifecycle

ApiClient creates fresh instances at src/ApiClient.php112-115 preventing state pollution:


5. Document Return Types

Delegation maintains return type compatibility, allowing fluent chaining and type-safe returns.

Sources: src/ApiClient.php10-115 src/ApiResource.php16-72


Summary

The hypervel/api-client package uses magic method delegation strategically at two points:

  1. ApiClient → PendingRequest: Provides a clean entry point while separating configuration from execution
  2. ApiResource → ApiResponse: Exposes response methods while maintaining encapsulation

Both implementations use the @mixin PHPDoc annotation for type safety and IDE support. The ApiResource implementation adds explicit validation for better error messages, while ApiClient optimizes for simplicity and fresh state isolation.

This delegation pattern enables the package's fluent, intuitive API while maintaining clean separation of concerns and proper encapsulation of internal implementation details.

Sources: src/ApiClient.php10-115 src/ApiResource.php16-72