<?php

/**
 * Created by PhpStorm.
 * User: filip
 * Date: 9/29/16
 * Time: 10:56 AM.
 */

/**
 * Trait MockingTrait.
 *
 * Extend a class you want to mock, override desired methods with body: `return $this->call(__FUNCTION__, func_get_args());`
 * Then just configure what you want to really override at runtime by setting callback via self::mock()
 * If no callback is provided vis self::mock(), parent method is called.
 */
trait MockingTrait
{
    private $methodMocks = [];

    public function mock($methodName, callable $methodBody)
    {
        if (!method_exists($this, $methodName)) {
            throw new \LogicException("Method '{$methodName}' does not exist on this object.");
        }
        $this->methodMocks[$methodName] = $methodBody;
    }

    private function call($methodName, $args)
    {
        if (isset($this->methodMocks[$methodName])) {
            return call_user_func_array($this->methodMocks[$methodName], $args);
        }

        return call_user_func_array("parent::{$methodName}", $args);
    }
}
