<?php
/* A view that calls another element's method dies where it calls when
that method is private or protected. PHP only complains when the line
runs, so a branch nobody has opened lately hides it: setting a wiki
page to the Git repository kind crashed that way, on a method the wiki
element had been calling all along.
This reads every call written as element("name")->method( or
helper("name")->method( and checks how that method is declared in the
matching element or helper class. A method declared private or
protected but called from another class is named.
php devlog/devscripts/check_cross_class_calls.php
*/
$kinds = ["element" => "src/views/elements", "helper" => "src/views/helpers"];
$declared = [];
foreach ($kinds as $kind => $folder) {
foreach (glob($folder . "/*.php") as $path) {
$class = basename($path, ".php");
$lines = file($path);
foreach ($lines as $one) {
if (preg_match('/^\s*(public|private|protected)\s+' .
'(?:static\s+)?function\s+(\w+)/', $one, $found)) {
$declared[$kind][strtolower($class)][$found[2]] =
$found[1];
}
}
}
}
$hidden = [];
$walk = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator("src"));
foreach ($walk as $file) {
if ($file->isDir() || substr($file->getFilename(), -4) !== ".php") {
continue;
}
$path = $file->getPathname();
$caller = basename($path, ".php");
$lines = file($path);
foreach ($lines as $at => $one) {
if (!preg_match_all('/(element|helper)\(\s*["\'](\w+)["\']\s*\)' .
'\s*->\s*(\w+)\s*\(/', $one, $found, PREG_SET_ORDER)) {
continue;
}
foreach ($found as $call) {
$kind = $call[1];
$named = strtolower($call[2]) .
(($kind == "element") ? "element" : "helper");
$method = $call[3];
/* A class calling its own method is free to reach a method
kept to itself, so only a call from elsewhere counts. */
if (strtolower($caller) === $named) {
continue;
}
$how = $declared[$kind][$named][$method] ?? "";
if ($how === "private" || $how === "protected") {
$hidden[] = basename($path) . ":" . ($at + 1) .
" calls " . $call[2] . " " . $kind . "'s " .
$method . ", which is " . $how;
}
}
}
}
$hidden = array_unique($hidden);
foreach ($hidden as $one) {
echo " " . $one . "\n";
}
echo "check: " . (count($hidden) ?
count($hidden) . " call(s) reach a method another class keeps to itself" :
"every cross-class call reaches a method open to it") . "\n";
exit(count($hidden) ? 1 : 0);