Skip to content

Commit

Permalink
Closure moved out from generated query code to prevent memory leak
Browse files Browse the repository at this point in the history
  • Loading branch information
remorhaz committed Apr 9, 2021
1 parent a4b23dc commit a7a0bf3
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 124 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.7.5] - 2021-04-10
### Fixed
- Closure moved out from generated query code to prevent memory leak (see https://bugs.php.net/bug.php?id=76982).

## [0.7.4] - 2021-01-15
### Added
- PHP 8.0 support.
Expand Down
60 changes: 13 additions & 47 deletions src/Query/CallbackBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@

use function array_map;
use function array_reverse;
use function is_callable;

final class CallbackBuilder extends AbstractTranslatorListener implements CallbackBuilderInterface
{
Expand Down Expand Up @@ -67,14 +66,21 @@ public function __construct()
$this->php = new BuilderFactory();
}

/**
* @noinspection PhpUnusedParameterInspection
*/
public function getCallback(): callable
{
if (!isset($this->callback)) {
$callback = eval($this->getCallbackCode());
if (!is_callable($callback)) {
throw new Exception\InvalidCallbackCodeException($this->getCallbackCode());
}
$this->callback = $callback;
$this->callback = function (
NodeValueListInterface $input,
ValueListFetcherInterface $valueListFetcher,
EvaluatorInterface $evaluator,
LiteralFactoryInterface $literalFactory,
MatcherFactoryInterface $matcherFactory
): ValueListInterface {
return eval($this->getCallbackCode());
};
}

return $this->callback;
Expand Down Expand Up @@ -113,54 +119,14 @@ public function onStart(QueryAstNode $node): void

public function onFinish(): void
{
$inputParam = $this
->php
->param(self::ARG_INPUT)
->setType(NodeValueListInterface::class)
->getNode();
$valueListFetcherParam = $this
->php
->param(self::ARG_VALUE_LIST_FETCHER)
->setType(ValueListFetcherInterface::class)
->getNode();
$evaluatorParam = $this
->php
->param(self::ARG_EVALUATOR)
->setType(EvaluatorInterface::class)
->getNode();
$literalFactoryParam = $this
->php
->param(self::ARG_LITERAL_FACTORY)
->setType(LiteralFactoryInterface::class)
->getNode();
$matcherFactoryParam = $this
->php
->param(self::ARG_MATCHER_FACTORY)
->setType(MatcherFactoryInterface::class)
->getNode();
$stmts = array_map(
function (PhpAstNode $stmt): PhpAstNode {
return $stmt instanceof Expr ? new Expression($stmt) : $stmt;
},
$this->stmts
);

$closure = new Expr\Closure(
[
'stmts' => $stmts,
'returnType' => ValueListInterface::class,
'params' => [
$inputParam,
$valueListFetcherParam,
$evaluatorParam,
$literalFactoryParam,
$matcherFactoryParam
],
]
);
$return = new Return_($closure);

$this->callbackCode = (new Standard())->prettyPrint([$return]);
$this->callbackCode = (new Standard())->prettyPrint($stmts);
}

public function onBeginProduction(QueryAstNode $node, PushInterface $stack): void
Expand Down
30 changes: 0 additions & 30 deletions src/Query/Exception/InvalidCallbackCodeException.php

This file was deleted.

47 changes: 0 additions & 47 deletions tests/Query/Exception/InvalidCallbackCodeExceptionTest.php

This file was deleted.

0 comments on commit a7a0bf3

Please sign in to comment.