Dynamically generate classes at runtime in php?

后端 未结 10 997
一向
一向 2020-12-09 15:06

Here\'s what I want to do:

$clsName = substr(md5(rand()),0,10); //generate a random name
$cls = new $clsName(); //create a new instance

function __autoload(         


        
相关标签:
10条回答
  • 2020-12-09 15:19

    We can create class instance dynamically by following way

    I also face this issue in Laravel 5.8 version and now it is working fine for me.

    Give full path instead of the class Name

    class TestController extends Controller
    {
        protected $className;
    
        public function __construct()
        {
            $this->className = 'User';
        }
    
        public function makeDynamicInstance()
        {
            $classNameWithPath = 'App\\' . $this->className; 
            $classInstance = new $classNameWithPath;
            $data = $classInstance::select('id','email')->get();
            return $data;
        }
    }
    

    Output

    Illuminate\Database\Eloquent\Collection Object
    (
        [items:protected] => Array
            (
                [0] => App\User Object
                    (
                        [fillable:protected] => Array
                            (
                                [0] => name
                                [1] => email
                                [2] => password
                                [3] => user_group_id
                                [4] => username
                                [5] => facebook_page_id
                                [6] => first_name
                                [7] => last_name
                                [8] => email_verified
                                [9] => active
                                [10] => mobile
                                [11] => user_type
                                [12] => alternate_password
                                [13] => salt
                                [14] => email_verification_token
                                [15] => parent_id
                            )
    
                        [hidden:protected] => Array
                            (
                                [0] => password
                                [1] => remember_token
                            )
    
                        [casts:protected] => Array
                            (
                                [email_verified_at] => datetime
                            )
    
                        [connection:protected] => mysql
                        [table:protected] => users
                        [primaryKey:protected] => id
                        [keyType:protected] => int
                        [incrementing] => 1
                        [with:protected] => Array
                            (
                            )
    
                        [withCount:protected] => Array
                            (
                            )
    
                        [perPage:protected] => 15
                        [exists] => 1
                        [wasRecentlyCreated] => 
                        [attributes:protected] => Array
                            (
                                [id] => 1
                                [email] => admin@admin.com
                            )
    
                        [original:protected] => Array
                            (
                                [id] => 1
                                [email] => admin@admin.com
                            )
    
                        [changes:protected] => Array
                            (
                            )
    
                        [dates:protected] => Array
                            (
                            )
    
                        [dateFormat:protected] => 
                        [appends:protected] => Array
                            (
                            )
    
                        [dispatchesEvents:protected] => Array
                            (
                            )
    
                        [observables:protected] => Array
                            (
                            )
    
                        [relations:protected] => Array
                            (
                            )
    
                        [touches:protected] => Array
                            (
                            )
    
                        [timestamps] => 1
                        [visible:protected] => Array
                            (
                            )
    
                        [guarded:protected] => Array
                            (
                                [0] => *
                            )
    
                        [rememberTokenName:protected] => remember_token
                    )
    )
    
    0 讨论(0)
  • 2020-12-09 15:21

    I know this is an old question and there are answers that WILL work, but I wanted to offer a few snippets that would answer the original question and I think offer a more expanded solution should someone end up here like I did when searching for an answer to this problem.

    Create Single Dynamic Class

    <?php
    // Without properties
    $myclassname = "anewclassname";
    eval("class {$myclassname} { }";
    // With a property
    $myclassname = "anewclassname";
    $myproperty = "newproperty";
    eval("class {$myclassname} { protected \${$myproperty}; }";
    ?>
    

    As long as you properly escape your text, you could also add a function in there.

    But what about if you want to dynamically create classes based on something that could itself be dynamic such as creating a class for each table in your database as the original question mentioned?

    Create Multiple Dynamic Classes

    <?php
    
    // Assumes $dbh is a pdo connection handle to your MySQL database
    $stmt=$dbh->prepare("show tables");
    $stmt->execute();
    $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
    $handle = null;
    $classcode = '';
    foreach ($result as $key => $value) {
        foreach ($value as $key => $value) {
            $classcode = "class {$value} { ";
            $stmt2=$dbh->prepare("DESC $value");
            $stmt2->execute();
            $result2 = $stmt2->fetchAll(PDO::FETCH_ASSOC);
            foreach ($result2 as $key => $value) {
                $classcode .= "public \${$value['Field']}; ";
            }
            $classcode .=  "}";
            eval($classcode);
        }
    }
    
    ?>
    

    This will dynamically generate a class for each table in a database. For each class, a property that is named after each column will ALSO get created.

    Now it's been pointed out you shouldn't do this. As long as you control what's going on in the eval, the risk of security isn't a problem. BUT -- there's most likely a solution that makes more sense if you think deeply enough about it. I thought I had the perfect use case for dynamically creating new classes. Careful examination of the problem proved otherwise.

    One potential solution -- use the stdClass for creating objects that are just data containers and don't need any methods.

    Also -- as mentioned, you could use a script to manually generate lots of classes. In the case of classes mirroring your database tables, you could use the same logic I have above and instead of doing an eval, write that info to a file.

    0 讨论(0)
  • 2020-12-09 15:21

    I have created a package that dynamically creates classes/interfaces/traits... and stores them into a file you can then just include the created file to be able to use your class

    package : https://packagist.org/packages/kanel/enuma

    0 讨论(0)
  • 2020-12-09 15:35

    its funny, actually this is one of the few things where eval doesnt seem such a bad idea.

    as long as you can ensure that no user input will ever enter the eval.

    you still have downsides like when your using a bytecode cache that code wont be cached etc etc. but the security issues of eval are pretty much related to having user inputy in the eval, or to ending up in the wrong scope.

    if you know what you are doing, eval will help you with this.

    That said, in my opinion you are much better off when you no rely on type-hinting for your validation, but you have one function

    DoSomething_Validate($id)
    { 
       // get_class($id) and other validation foo here
    }
    
    0 讨论(0)
  • 2020-12-09 15:41

    Using eval() is really a bad idea. It opens a large security hole. Just don't use it!

    0 讨论(0)
  • 2020-12-09 15:42

    As of PHP 7.0, with a little creativity and knowledge of some lesser known PHP features, you can absolutely do this without resorting to eval or creating script files dynamically. You just need to use anonymous classes and class_alias(), like such:

    spl_autoload_register(function ($unfoundClassName) {
    {
        $newClass = new class{}; //create an anonymous class
        $newClassName = get_class($newClass); //get the name PHP assigns the anonymous class
        class_alias($newClassName, $unfoundClassName); //alias the anonymous class with your class name
    }
    

    This works because anonymous classes are still assigned a name behind the scenes and put in the global scope, so you're free to grab that class name and alias it. Check out the second comment under the anonymous classes link above for more information.

    Having said that, I feel like all the people in this question who are saying "Eval is always a very bad idea. Just don't use it ever!" are just repeating what they've heard from the hive mind and not thinking for themselves. Eval is in the language for a reason, and there are situations where it can be used effectively. If you're on an older version of PHP, eval might be a good solution here.

    However, they are correct in that it can open up very large security holes and you have to be careful how you use it and understand how to eliminate the risks. The important thing is, much like SQL injection, you have to sanitize any input you put in the eval statement.

    For example, if your autoloader looked like this:

    spl_autoload_register(function ($unfoundClassName) {
    {
        eval("class $unfoundClassName {}");
    }
    

    A hacker could do something like this:

    $injectionCode = "bogusClass1{} /*insert malicious code to run on the server here */ bogusClass2";
    
    new $injectionCode();
    

    See how this has the potential to be a security hole? Anything the hacker puts between the two bogusClass names will be run on your server by the eval statement.

    If you adjust your autoloader to check the class name passed in (i.e. doing a preg_match to make sure there's no spaces or special characters, checking it against a list of acceptable names, etc.), you can eliminate these risks and then eval might be totally fine to use in this situation. If you're on PHP 7 or higher though, I recommend the anonymous class alias method above.

    0 讨论(0)
提交回复
热议问题