8000 Tool - Dynamically Declared Properties Auto Detection · Issue #6291 · bcit-ci/CodeIgniter · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
Tool - Dynamically Declared Properties Auto Detection #6291
Open
@juanluislopez89

Description

@juanluislopez89

Hi! i Just made this controller to analyze wheter a system class has dynamically declared properties. Ithink this may help to adapt CI3 to the neew PHP 8.3 without using [#AllowDynamicProperties] argument that can be depecated in future versions.

Cannot detect if a property is inherited! so in some cases, there can be false positives.

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Analyze_dynamic_properties extends CI_Controller {

    public function __construct()
    {
        parent::__construct();
    }

    public function index()
    {
        $directory = SYSDIR;
        $dynamicProperties = $this->findDynamicProperties($directory);

        // Renderizar la vista directamente aquí
        echo $this->renderView($dynamicProperties);
    }

    private function findDynamicProperties($dir)
    {
        $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
        $dynamicProperties = [];

        foreach ($files as $file) {
            if ($file->isDir() || $file->getExtension() !== 'php') {
                continue;
            }

            $content = file_get_contents($file->getRealPath());
            $tokens = token_get_all($content);
            $classes = [];
            $currentClass = '';
            $collectingClass = false;
            $declaredProperties = [];

            for ($i = 0; $i < count($tokens); $i++) {
                $token = $tokens[$i];

                if (is_array($token)) {
                    if ($token[0] === T_CLASS) {
                        $collectingClass = true;
                    } elseif ($collectingClass && $token[0] === T_STRING) {
                        $currentClass = $token[1];
                        $classes[$currentClass] = ['file' => $file->getRealPath(), 'properties' => [], 'declared' => []];
                        $collectingClass = false;
                    } elseif ($currentClass && $token[0] === T_VARIABLE && $token[1] === '$this') {
                        $nextToken = $tokens[$i + 1] ?? null;
                        if (is_array($nextToken) && $nextToken[0] === T_OBJECT_OPERATOR) {
                            $propertyToken = $tokens[$i + 2] ?? null;
                            $assignmentToken = $tokens[$i + 4] ?? null;
                            if (is_array($propertyToken) && $propertyToken[0] === T_STRING && $assignmentToken === '=') {
                                $propertyName = $propertyToken[1];
                                if (!in_array($propertyName, $declaredProperties) && !in_array($propertyName, $classes[$currentClass]['declared'])) {
                                    $classes[$currentClass]['properties'][] = [
                                        'name' => $propertyName,
                                        'declared' => false
                                    ];
                                }
                            }
                        }
                    } elseif ($currentClass && $token[0] === T_VARIABLE) {
                        $declaredProperties[] = substr($token[1], 1);
                    } elseif ($currentClass && $token[0] === T_PUBLIC) {
                        $nextToken = $tokens[$i + 2] ?? null;
                        if (is_array($nextToken) && $nextToken[0] === T_VARIABLE) {
                            $declaredPropertyName = substr($nextToken[1], 1);
                            $classes[$currentClass]['declared'][] = $declaredPropertyName;
                            $classes[$currentClass]['properties'][] = [
                                'name' => $declaredPropertyName,
                                'declared' => true
                            ];
                        }
                    }
                }
            }

            foreach ($classes as $className => $data) {
                if (!empty($data['properties'])) {
                    $dynamicProperties[$className]['file'] = $data['file'];
                    $dynamicProperties[$className]['properties'] = $data['properties'];
                }
            }
        }

        return $dynamicProperties;
    }

    private function renderView($dynamicProperties)
    {
        ob_start();
        ?>
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>PHP 8 Compatibility Analysis</title>
            <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
            <style>
                .table td.success {
                    background-color: #dff0d8;
                }
                .table td.danger {
                    background-color: #f2dede;
                }
            </style>
        </head>
        <body>
        <div class="container">
            <h1>PHP 8 Compatibility Analysis</h1><hr>
            <div class="btn-group" role="group" aria-label="Filter Buttons">
                <button type="button" class="btn btn-success" >Good Classes</button>
                <button type="button" class="btn btn-danger" >Wrong Classes</button>
                <button type="button" class="btn btn-primary" >All Classes</button>
            </div>
            <hr>
            <table class="table table-bordered table-striped" id="resultsTable">
                <thead>
                <tr>
                    <th>Class</th>
                    <th>File</th>
                    <th>Property</th>
                    <th>Status</th>
                </tr>
                </thead>
                <tbody>
                <?php foreach ($dynamicProperties as $className => $data): ?>
                    <?php 
                    $classStatus = 'good'; 
                    foreach ($data['properties'] as $property): 
                        if (!$property['declared']) {
                            $classStatus = 'bad';
                            break;
                        }
                    endforeach;
                    ?>
                    <?php foreach ($data['properties'] as $index => $property): ?>
                    <tr class="<?= $classStatus ?>">
                        <?php if ($index === 0): ?>
                            <td rowspan="<?= count($data['properties']) ?>"><?= $className ?></td>
                            <td rowspan="<?= count($data['properties']) ?>"><?= $data['file'] ?></td>
                        <?php endif; ?>
                        <td class="<?= $property['declared'] ? 'success' : 'danger' ?>"><?= $property['name'] ?></td>
                        <td class="<?= $property['declared'] ? 'success' : 'danger' ?>">
                            <strong class="text-<?= $property['declared'] ? 'success' : 'danger' ?>"><?= $property['declared'] ? 'Declared =)' : 'Not Declared !!!' ?></strong>
                        </td>
                    </tr>
                    <?php endforeach; ?>
                <?php endforeach; ?>
                </tbody>
            </table>
        </div>

        <script>
            function filterClasses(status) {
                var rows = document.querySelectorAll('#resultsTable tbody tr');
                rows.forEach(function (row) {
                    if (status === 'all') {
                        row.st
5258
yle.display = '';
                    } else if (status === 'good' && row.classList.contains('good')) {
                        row.style.display = '';
                    } else if (status === 'bad' && row.classList.contains('bad')) {
                        row.style.display = '';
                    } else {
                        row.style.display = 'none';
                    }
                });
            }
        </script>
        </body>
        </html>
        <?php
        return ob_get_clean();
    }
}
`

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0