<commit_before><?php
/**
 * This file is part of FunctionInjector project.
 * You are using it at your own risk and you are fully responsible for everything that code will do.
 *
 * Copyright (c) 2016 <NAME> <<EMAIL>>
 *
 * For the full copyright and license information, please view the LICENSE file distributed with this source code.
 */

namespace noFlash\FunctionsManipulator;

use noFlash\FunctionsManipulator\Exception\IncompleteInjectableException;
use noFlash\FunctionsManipulator\Exception\InjectionMismatchException;
use noFlash\FunctionsManipulator\Exception\RedeclareException;
use noFlash\FunctionsManipulator\Exception\ScopeGenerationLimitException;
use noFlash\FunctionsManipulator\Exception\ScopeNotFoundException;
use noFlash\FunctionsManipulator\Injectable\InjectableInterface;

class FunctionInjector
{
    /**
     * @var string sprintf()-complaint pattern for scope generation
     * @internal
     */
    const FAKE_SCOPE_PATTERN = '_noFlash_FunctionsManipulator_fakeScope_%s';

    /**
     * @var string How many times script should try to find unique scope key.
     * @internal
     */
    const SCOPE_KEY_MAX_LOOPS = 100;

    protected function getUniqueScopeKey()
    {
        for ($i = 0; $i < static::SCOPE_KEY_MAX_LOOPS; $i++) {
            $key = sprintf(static::FAKE_SCOPE_PATTERN, sha1(uniqid()));

            if (!isset($GLOBALS[$key])) {
                return $key;
            }
        }

        throw new ScopeGenerationLimitException(static::SCOPE_KEY_MAX_LOOPS);
    }

    private function getInjectionCode($scopeId, InjectableInterface $injection)
    {
        $ns = trim($injection->getNamespace(), '\\');

        $injectionCode = <<<CODE
namespace $ns {
    function {$injection->getFunctionName()}(...\$args) {
        return \$GLOBALS['$scopeId']->getCallback()(...\$args);
    }
}
CODE;

        return $injectionCode;
    }

    public function injectFunction(InjectableInterface $injection)
    {
        $functionName = $injection->getFunctionName();
        if ($functionName === null) {
            throw new IncompleteInjectableException(
                'Passed injectable lacks function name'
            );
        }

        $ns = trim($injection->getNamespace(), '\\');
        $accessor = '\\' . ((empty($ns)) ? $functionName : ($ns . '\\' . $functionName));
        if (function_exists($accessor)) {
            throw new RedeclareException($ns, $functionName);
        }

        $scopeId = $this->getUniqueScopeKey();
        $GLOBALS[$scopeId] = $injection;
        $injectionCode = $this->getInjectionCode($scopeId, $injection);

        //The only valid use-case for eval() in my career...
        eval($injectionCode);

        return $scopeId;
    }

    public function replaceFunctionInjection($scopeId, InjectableInterface $inj)
    {
        if (!isset($GLOBALS[$scopeId]) ||
            !($GLOBALS[$scopeId] instanceof InjectableInterface)
        ) {
            throw new ScopeNotFoundException($scopeId);
        }

        /** @var InjectableInterface $oldInjection */
        $oldInjection = $GLOBALS[$scopeId];

        $oldNS = $oldInjection->getNamespace();
        $newNS = $inj->getNamespace();
        if ($newNS !== null && $oldNS !== $newNS) {<commit_msg>Fixed closure calls for PHP <7<commit_after><?php
/**
 * This file is part of FunctionInjector project.
 * You are using it at your own risk and you are fully responsible for everything that code will do.
 *
 * Copyright (c) 2016 <NAME> <<EMAIL>>
 *
 * For the full copyright and license information, please view the LICENSE file distributed with this source code.
 */

namespace noFlash\FunctionsManipulator;

use noFlash\FunctionsManipulator\Exception\IncompleteInjectableException;
use noFlash\FunctionsManipulator\Exception\InjectionMismatchException;
use noFlash\FunctionsManipulator\Exception\RedeclareException;
use noFlash\FunctionsManipulator\Exception\ScopeGenerationLimitException;
use noFlash\FunctionsManipulator\Exception\ScopeNotFoundException;
use noFlash\FunctionsManipulator\Injectable\InjectableInterface;

class FunctionInjector
{
    /**
     * @var string sprintf()-complaint pattern for scope generation
     * @internal
     */
    const FAKE_SCOPE_PATTERN = '_noFlash_FunctionsManipulator_fakeScope_%s';

    /**
     * @var string How many times script should try to find unique scope key.
     * @internal
     */
    const SCOPE_KEY_MAX_LOOPS = 100;

    protected function getUniqueScopeKey()
    {
        for ($i = 0; $i < static::SCOPE_KEY_MAX_LOOPS; $i++) {
            $key = sprintf(static::FAKE_SCOPE_PATTERN, sha1(uniqid()));

            if (!isset($GLOBALS[$key])) {
                return $key;
            }
        }

        throw new ScopeGenerationLimitException(static::SCOPE_KEY_MAX_LOOPS);
    }

    private function getInjectionCode($scopeId, InjectableInterface $injection)
    {
        $ns = trim($injection->getNamespace(), '\\');

        $injectionCode = <<<CODE
namespace $ns {
    function {$injection->getFunctionName()}(...\$args) {
        \$cb = \$GLOBALS['$scopeId']->getCallback();
        return \$cb(...\$args);
    }
}
CODE;

        return $injectionCode;
    }

    public function injectFunction(InjectableInterface $injection)
    {
        $functionName = $injection->getFunctionName();
        if ($functionName === null) {
            throw new IncompleteInjectableException(
                'Passed injectable lacks function name'
            );
        }

        $ns = trim($injection->getNamespace(), '\\');
        $accessor = '\\' . ((empty($ns)) ? $functionName : ($ns . '\\' . $functionName));
        if (function_exists($accessor)) {
            throw new RedeclareException($ns, $functionName);
        }

        $scopeId = $this->getUniqueScopeKey();
        $GLOBALS[$scopeId] = $injection;
        $injectionCode = $this->getInjectionCode($scopeId, $injection);

        //var_dump($injectionCode);
        //The only valid use-case for eval() in my career...
        eval($injectionCode);

        return $scopeId;
    }

    public function replaceFunctionInjection($scopeId, InjectableInterface $inj)
    {
        if (!isset($GLOBALS[$scopeId]) ||
            !($GLOBALS[$scopeId] instanceof InjectableInterface)
        ) {
            throw new ScopeNotFoundException($scopeId);
        }

        /** @var InjectableInterface $oldInjection */
        $oldInjection = $GLOBALS[$scopeId];

        $oldNS = $oldInjection->getNamespace();
        $newNS = $inj->getNamespace();
        if ($newNS !== null && $oldNS !== $newNS) {
{'fraction_non_alphanumeric': 0.1228310502283105, 'fraction_numerical': 0.00289193302891933, 'mean_word_length': 2.934730538922156, 'pattern_counts': {'":': 0, '<': 20, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5291342', 'n_tokens_mistral': 1933, 'n_tokens_neox': 1819, 'n_words': 420}