68 public static function dumpMemory(mixed $startingObject,
string $outputFolder,
int $maxNesting,
int $maxStringSize, \
Logger $logger) : void{
69 $hardLimit =
Utils::assumeNotFalse(ini_get(
'memory_limit'),
"memory_limit INI directive should always exist");
70 ini_set(
'memory_limit',
'-1');
71 $gcEnabled = gc_enabled();
74 if(!file_exists($outputFolder)){
75 mkdir($outputFolder, 0777,
true);
78 $obData = Utils::assumeNotFalse(fopen(Path::join($outputFolder,
"objects.js"),
"wb+"));
86 $staticProperties = [];
89 $functionStaticVars = [];
90 $functionStaticVarsCount = 0;
92 foreach(get_declared_classes() as $className){
93 $reflection = new \ReflectionClass($className);
94 $staticProperties[$className] = [];
95 foreach($reflection->getProperties() as $property){
96 if(!$property->isStatic() || $property->getDeclaringClass()->getName() !== $className){
100 if(!$property->isInitialized()){
105 $staticProperties[$className][$property->getName()] = self::continueDump($property->getValue(), $objects, $refCounts, 0, $maxNesting, $maxStringSize);
108 if(count($staticProperties[$className]) === 0){
109 unset($staticProperties[$className]);
112 foreach($reflection->getMethods() as $method){
113 if($method->getDeclaringClass()->getName() !== $reflection->getName()){
117 foreach(Utils::promoteKeys($method->getStaticVariables()) as $name => $variable){
118 $methodStatics[$name] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
120 if(count($methodStatics) > 0){
121 $functionStaticVars[$className .
"::" . $method->getName()] = $methodStatics;
122 $functionStaticVarsCount += count($functionStaticVars);
127 file_put_contents(Path::join($outputFolder,
"staticProperties.js"), json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
128 $logger->
info(
"Wrote $staticCount static properties");
130 $globalVariables = [];
145 foreach(Utils::promoteKeys($GLOBALS) as $varName => $value){
146 if(isset($ignoredGlobals[$varName])){
151 $globalVariables[$varName] = self::continueDump($value, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
154 file_put_contents(Path::join($outputFolder,
"globalVariables.js"), json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
155 $logger->
info(
"Wrote $globalCount global variables");
157 foreach(get_defined_functions()[
"user"] as $function){
158 $reflect = new \ReflectionFunction($function);
161 foreach(Utils::promoteKeys($reflect->getStaticVariables()) as $varName => $variable){
162 $vars[$varName] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
164 if(count($vars) > 0){
165 $functionStaticVars[$function] = $vars;
166 $functionStaticVarsCount += count($vars);
169 file_put_contents(Path::join($outputFolder,
'functionStaticVars.js'), json_encode($functionStaticVars, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
170 $logger->
info(
"Wrote $functionStaticVarsCount function static variables");
172 $data = self::continueDump($startingObject, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
176 foreach(Utils::stringifyKeys($objects) as $hash => $object){
177 if(!is_object($object)){
182 $className = get_class($object);
183 if(!isset($instanceCounts[$className])){
184 $instanceCounts[$className] = 1;
186 $instanceCounts[$className]++;
189 $objects[$hash] =
true;
191 "information" =>
"$hash@$className",
193 if($object instanceof \Closure){
194 $info[
"definition"] = Utils::getNiceClosureName($object);
195 $info[
"referencedVars"] = [];
196 $reflect = new \ReflectionFunction($object);
197 if(($closureThis = $reflect->getClosureThis()) !==
null){
198 $info[
"this"] = self::continueDump($closureThis, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
201 foreach(Utils::promoteKeys($reflect->getStaticVariables()) as $name => $variable){
202 $info[
"referencedVars"][$name] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
205 $reflection = new \ReflectionObject($object);
207 $info[
"properties"] = [];
209 for($original = $reflection; $reflection !==
false; $reflection = $reflection->getParentClass()){
210 foreach($reflection->getProperties() as $property){
211 if($property->isStatic()){
215 $name = $property->getName();
216 if($reflection !== $original){
217 if($property->isPrivate()){
218 $name = $reflection->getName() .
":" . $name;
223 if(!$property->isInitialized($object)){
227 $info[
"properties"][$name] = self::continueDump($property->getValue($object), $objects, $refCounts, 0, $maxNesting, $maxStringSize);
232 fwrite($obData, json_encode($info, JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) .
"\n");
237 $logger->
info(
"Wrote " . count($objects) .
" objects");
241 file_put_contents(Path::join($outputFolder,
"serverEntry.js"), json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
242 file_put_contents(Path::join($outputFolder,
"referenceCounts.js"), json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
244 arsort($instanceCounts, SORT_NUMERIC);
245 file_put_contents(Path::join($outputFolder,
"instanceCounts.js"), json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
247 $logger->
info(
"Finished!");
249 ini_set(
'memory_limit', $hardLimit);