From a66e5805cc111c87f22d3ea8f4590797a7f7b652 Mon Sep 17 00:00:00 2001 From: Dan Wells Date: Thu, 18 May 2017 16:50:05 -0400 Subject: [PATCH 1/4] Add proper PHP tag PHP no longer supports " --- packages/collections/pub/eadlist.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/collections/pub/eadlist.php b/packages/collections/pub/eadlist.php index 38f850c..0f6f285 100644 --- a/packages/collections/pub/eadlist.php +++ b/packages/collections/pub/eadlist.php @@ -36,7 +36,7 @@ { ?> &templateset=ead&disabletheme=1&output='>
- Date: Thu, 18 May 2017 16:41:42 -0400 Subject: [PATCH 2/4] Fix non-static variable access $OutputQueries is not static, so we need $this here. Older versions of PHP (<7.0) were more lax about this, particular the way we were mixing contexts. Signed-off-by: Dan Wells --- packages/core/lib/querylog.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/lib/querylog.inc.php b/packages/core/lib/querylog.inc.php index 66c8a43..6930086 100755 --- a/packages/core/lib/querylog.inc.php +++ b/packages/core/lib/querylog.inc.php @@ -5,7 +5,7 @@ public function logQuery(&$DB, $Scope, $Message, $IsManip = NULL) { $this->QueryCount++; - if($OutputQueries) + if($this->OutputQueries) { echo("\n\n$Message\n\n"); } From 710a1b44770a2a9b32a01ef5eb8f1a2a29d1209b Mon Sep 17 00:00:00 2001 From: Dan Wells Date: Thu, 24 Aug 2017 16:38:13 -0400 Subject: [PATCH 3/4] PHP 7.1+ compatibility workaround Our workaround for PHP 7.0 broke on 7.1. This is another workaround, though even more tenuous in nature than the first. Similar to our original goal, we're trying to keep changes to a minimum, not write an ideal and long-term solution. Our old solution stopped working due to changes in PHP 7.1 as expressed by NikiC here: https://stackoverflow.com/questions/47165930/php-binding-method-to-another-class For further reference, here is the commit message from our original PHP 7.0 fix: Archon's object composition technique makes heavy use of a PHP feature allowing method calls from an incompatible context. However, this ability was deprecated in PHP 5.6 and removed from PHP 7.0 [1]. Ultimately, it seems like moving over to Traits may be a logical path forward. This patch instead attempts to allow current Archon to run on PHP 7+ with the fewest changes possible. Rather than simply attempt the method call in the wrong context, we instead create a closure in the desired class, then insert our current context into that closure using bindTo. There may, of course, be a simpler way to do this. In particular, it seems messy to need to create an object only to get the closure. I do not claim to be an expert in PHP internals, but this functions, and is decently boiled down. This new technique should be supported for PHP >= 5.4.0, but this is untested. One questionable area would be the use of the getClosure method call on a parenthesized "new" object statement. I believe it is supported syntax on at least 5.6, and would be very easy to work around in any case. That said, it may be better to retain the old technique and branch within the code to suit the running version. [1] http://php.net/manual/en/migration56.deprecated.php#migration56.deprecated.incompatible-context Signed-off-by: Dan Wells --- packages/core/lib/archon.inc.php | 12 +++++++-- packages/core/lib/archonobject.inc.php | 37 ++++++++++++++------------ 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/packages/core/lib/archon.inc.php b/packages/core/lib/archon.inc.php index d4a29b2..fdede73 100755 --- a/packages/core/lib/archon.inc.php +++ b/packages/core/lib/archon.inc.php @@ -2682,8 +2682,16 @@ public function initialize() continue; } - //$result = call_user_func(array($MixinClass, initialize)); - eval("\$result = {$MixinClass}::initialize();"); + // This may not be quite correct, but is working for current usage of this code. + // See the mixin technique in archonobject.inc.php for an alternative. + $myMixinClass = "___{$MixinClass}___"; + if (!class_exists($myMixinClass)) { + eval("class $myMixinClass extends $MixinClass {}"); + } + $mixin = new $myMixinClass; + $closure = (new ReflectionMethod($myMixinClass, 'initialize'))->getClosure($mixin); + $result = call_user_func($closure->bindTo($this)); + } } diff --git a/packages/core/lib/archonobject.inc.php b/packages/core/lib/archonobject.inc.php index c1b3742..ec15d4a 100755 --- a/packages/core/lib/archonobject.inc.php +++ b/packages/core/lib/archonobject.inc.php @@ -10,20 +10,14 @@ public function callOverridden() $args = func_get_args(); $MixinClass = prev($methodInfo->Classes); - $arrStrArgs = array(); - - for($i = 0; $i < count($args); $i++) - { - $arrStrArgs[] = "\$args[{$i}]"; - } - // Simulate mixing after. if($_ARCHON->Mixins[get_class($this)]->Methods[$method]->Parameters[$MixinClass]->MixOrder == MIX_AFTER) { $prevresult = call_user_func_array(array($this, 'callOverridden'), $args); } - eval("\$result = {$MixinClass}::{$method}(" . implode(',', $arrStrArgs) . ");"); + $closure = $this->__getMixinClosure($MixinClass, $method); + $result = call_user_func_array($closure->bindTo($this), $args); // Simulate mixing before. if($_ARCHON->Mixins[get_class($this)]->Methods[$method]->Parameters[$MixinClass]->MixOrder == MIX_BEFORE) @@ -235,21 +229,14 @@ public function __call($method, $args) $_ARCHON->Callstack[] = $stackmember; $MixinClass = end(end($_ARCHON->Callstack)->Classes); - $arrStrArgs = array(); - - for($i = 0; $i < count($args); $i++) - { - $arrStrArgs[] = "\$args[{$i}]"; - } - // Simulate mixing after. if($_ARCHON->Mixins[get_class($this)]->Methods[$method]->Parameters[$MixinClass]->MixOrder == MIX_AFTER) { $prevresult = call_user_func_array(array($this, 'callOverridden'), $args); } - eval("\$result = {$MixinClass}::{$method}(" . implode(',', $arrStrArgs) . ");"); - //$result = call_user_func_array(array(($MixinClass) $this, $method), $args); + $closure = $this->__getMixinClosure($MixinClass, $method); + $result = call_user_func_array($closure->bindTo($this), $args); // Simulate mixing before. if($_ARCHON->Mixins[get_class($this)]->Methods[$method]->Parameters[$MixinClass]->MixOrder == MIX_BEFORE) @@ -308,5 +295,21 @@ public function __toString() return get_class($this); } } + + + private function __getMixinClosure($MixinClass, $mixinMethod) { + $method = new ReflectionMethod($MixinClass, $mixinMethod); + $start = $method->getStartLine() - 1; + $length = $method->getEndLine() - $start; + + $source = file($method->getFileName()); + $method_body = implode("", array_slice($source, $start, $length)); + $method_body = preg_replace("/$mixinMethod/", "", $method_body, 1); + $method_body = preg_replace("/public/", "", $method_body, 1); + eval('$closure = '.$method_body.';'); + + return $closure; + } + } ?> From bb7ab95cf1e26723000d75fe0e7f779b04e9c726 Mon Sep 17 00:00:00 2001 From: Dan Wells Date: Mon, 11 Mar 2019 17:06:33 -0400 Subject: [PATCH 4/4] Extend new technique to Core_Archon The previous commit left the "old" workaround in place in Core_Archon, as the code appeared to work, and we were interested in making fewer changes. However, it appears the above code branch is used exactly once in Archon (the Collections core mixin), and the initialize function there was simply not running. This change gets it to run again as expected. Signed-off-by: Dan Wells --- packages/core/lib/archon.inc.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/packages/core/lib/archon.inc.php b/packages/core/lib/archon.inc.php index fdede73..2c17126 100755 --- a/packages/core/lib/archon.inc.php +++ b/packages/core/lib/archon.inc.php @@ -2682,15 +2682,7 @@ public function initialize() continue; } - // This may not be quite correct, but is working for current usage of this code. - // See the mixin technique in archonobject.inc.php for an alternative. - $myMixinClass = "___{$MixinClass}___"; - if (!class_exists($myMixinClass)) { - eval("class $myMixinClass extends $MixinClass {}"); - } - $mixin = new $myMixinClass; - $closure = (new ReflectionMethod($myMixinClass, 'initialize'))->getClosure($mixin); - $result = call_user_func($closure->bindTo($this)); + $closure = $this->__getMixinClosure($MixinClass, 'initialize'); } }