This article details how to use the Nikic PhpParser library to programmatically modify array variables in PHP files, specifically how to correctly add new elements to existing arrays. By parsing PHP code into an abstract syntax tree (AST), the article demonstrates the correct method of identifying the target array when traversing the AST, and using AST node classes such as `PhpParser\Node\Expr\ArrayItem` and `PhpParser\Node\Scalar\String_` to construct and insert new array items, avoiding errors caused by directly mixing original data and AST nodes.
Use Nikic PhpParser to modify array variables in PHP files
When performing tasks such as code automation, refactoring or static analysis, we may need to programmatically read, analyze or even modify PHP code. Nikic PhpParser is a powerful tool that parses PHP code into abstract syntax trees (AST) and allows us to traverse and manipulate these tree structures. This article will focus on how to use Nikic PhpParser to modify array variables in PHP files, especially how to correctly add new key-value pairs to existing arrays.
1. Preparation: Parsing PHP code
First, we need a PHP file containing the target array variable. Suppose we have the first.php file with the following content:
<?php define("CONSTANT1", "cons1value"); $variable1 = "var1value"; $variable2 = array( "key1" => "value1", "key2" => "value2" );
Our goal is to modify $variable2 to:
<?php define("CONSTANT1", "cons1value_updated"); $variable1 = "var1value_updated"; $variable2 = array( "key1" => "value1_updated", "key2" => "value2", // Assume this value remains unchanged, or modify it as needed "key_3_added" => "value3_added" );
To achieve this, we need to use Nikic PhpParser to parse the first.php file and get its AST.
<?php require 'vendor/autoload.php'; // Make sure the Composer autoloader is configured use PhpParser\Error; use PhpParser\ParserFactory; use PhpParser\NodeTraverser; use PhpParser\PrettyPrinter\Standard; use PhpParser\Node\Expr\ArrayItem; use PhpParser\Node\Scalar\String_; use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\Array_; use PhpParser\Node\Expr\Variable; $parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7); $prettyPrinter = new Standard; $traverser = new NodeTraverser; $source = file_get_contents("first.php"); try { $stmts = $parser->parse($source); // Here we can add a custom NodeVisitor to handle modifications // $traverser->addVisitor(new MyNodeVisitor()); // $stmts = $traverser->traverse($stmts); } catch (Error $error) { echo "Parse error: {$error->getMessage()}\n"; exit(); } // $stmts now contains the abstract syntax tree of first.php
2. Traverse the AST and locate the target array
In order to modify $variable2, we need to traverse the AST and find the corresponding variable assignment statement. In AST, variable assignment is usually represented as a PhpParser\Node\Expr\Assign node, with variables on the left (PhpParser\Node\Expr\Variable) and values ??on the right (e.g. PhpParser\Node\Expr\Array_).
// ... (continued from above code) foreach ($stmts as $stmt) { // Check whether it is an expression statement (ExprStmt) and the expression is an assignment operation (Assign) if ($stmt instanceof PhpParser\Node\Stmt\Expression && $stmt->expr instanceof Assign) { $assign = $stmt->expr; // Check whether the left side of the assignment is a variable if ($assign->var instanceof Variable) { // Check if the variable name is 'variable2' if ($assign->var->name === 'variable2') { // Check whether the right side of the assignment is an array if ($assign->expr instanceof Array_) { $arrayNode = $assign->expr; // Now $arrayNode is the array node we want to modify // Loop through the existing array items and modify the value of 'key1' foreach ($arrayNode->items as $item) { if ($item instanceof ArrayItem && $item->key instanceof String_) { switch ($item->key->value) { case 'key1': // Modify the value of 'key1' $item->value = new String_("value1_updated"); break; case 'key2': // Assume we also want to modify 'key2' // $item->value = new String_("value2_updated"); break; } } } // Try to add new elements // Wrong way: add PHP array directly // $arrayNode->items[] = ["key3_added" => "value3_added"]; // This causes an error because the AST node list expects an AST node object, not a raw PHP array. } } } } } // Print the modified code // echo $prettyPrinter->prettyPrintFile($stmts);
3. Add new array elements correctly
In the above code, it is wrong to directly add the PHP array ["key3_added" => "value3_added"] to $arrayNode->items. Nikic PhpParser deals with abstract syntax trees, and $arrayNode->items expects objects of type PhpParser\Node\Expr\ArrayItem, not ordinary PHP arrays.
To properly add a key-value pair, we need to construct an ArrayItem node containing the key and value as PhpParser\Node\Scalar\String_ or other appropriate expression node.
// ... (continued from above code) foreach ($stmts as $stmt) { if ($stmt instanceof PhpParser\Node\Stmt\Expression && $stmt->expr instanceof Assign) { $assign = $stmt->expr; if ($assign->var instanceof Variable && $assign->var->name === 'variable2') { if ($assign->expr instanceof Array_) { $arrayNode = $assign->expr; // Traverse and modify existing items foreach ($arrayNode->items as $item) { if ($item instanceof ArrayItem && $item->key instanceof String_) { if ($item->key->value === 'key1') { $item->value = new String_("value1_updated"); } } } // Add new elements correctly // Create a string node representing the new key $newKey = new String_("key_3_added"); // Create a string node representing the new value $newValue = new String_("value3_added"); //Create an ArrayItem node and associate keys and values ??$newArrayItem = new ArrayItem($newValue, $newKey); //Add the newly created ArrayItem node to the items list of the array node $arrayNode->items[] = $newArrayItem; // You can also write it directly in one line // $arrayNode->items[] = new ArrayItem(new String_("value3_added"), new String_("key_3_added")); } } } } //Print the modified code echo $prettyPrinter->prettyPrintFile($stmts);
Running the above code, you will get the following output (or similar format, depending on PrettyPrinter's configuration):
<?php define("CONSTANT1", "cons1value"); $variable1 = "var1value"; $variable2 = array( "key1" => "value1_updated", "key2" => "value2", "key_3_added" => "value3_added" );
4. Complete sample code
To show the entire process more clearly, here is a complete example with all the steps:
<?php require 'vendor/autoload.php'; use PhpParser\Error; use PhpParser\ParserFactory; use PhpParser\NodeTraverser; use PhpParser\PrettyPrinter\Standard; use PhpParser\Node\Expr\ArrayItem; use PhpParser\Node\Scalar\String_; use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\Array_; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Stmt\Expression; //Introduce Expression node // 1. Create a sample PHP file file_put_contents('first.php', '<?php define("CONSTANT1", "cons1value"); $variable1 = "var1value"; $variable2 = array( "key1" => "value1", "key2" => "value2" ); '); // 2. Initialize the parser and printer $parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7); $prettyPrinter = new Standard; $traverser = new NodeTraverser; // Although this example traverses directly, NodeTraverser is a more general method $source = file_get_contents("first.php"); try { $stmts = $parser->parse($source); } catch (Error $error) { echo "Parse error: {$error->getMessage()}\n"; exit(); } // 3. Traverse the AST and modify it foreach ($stmts as $stmt) { // Check if it is an expression statement (Stmt\Expression) if ($stmt instanceof Expression && $stmt->expr instanceof Assign) { $assign = $stmt->expr; // Check whether the left side of the assignment is a variable and the variable name is 'variable2' if ($assign->var instanceof Variable && $assign->var->name === 'variable2') { // Check whether the right side of the assignment is an array if ($assign->expr instanceof Array_) { $arrayNode = $assign->expr; // Loop through existing array items and modify the value of 'key1' foreach ($arrayNode->items as $item) { if ($item instanceof ArrayItem && $item->key instanceof String_) { if ($item->key->value === 'key1') { // Modify the value of 'key1' $item->value = new String_("value1_updated"); } } } // Add new array element 'key_3_added' => 'value3_added' $arrayNode->items[] = new ArrayItem( new String_("value3_added"), // Value node new String_("key_3_added") // Key node); } } } } // 4. Print the modified code $modifiedCode = $prettyPrinter->prettyPrintFile($stmts); echo "--- Modified PHP Code ---\n"; echo $modifiedCode; // 5. Clean up the sample file unlink('first.php');
5. Notes and Summary
- Understand the AST structure: The core of Nikic PhpParser is the abstract syntax tree. All code elements are represented as specific PhpParser\Node objects. When you need to modify or add code, you must use the corresponding Node subclass to construct it.
- Distinguish raw data from AST nodes: This is a common pitfall. For example, in array operations, $arrayNode->items is a list of ArrayItem objects, not a list of ordinary PHP arrays. Trying to add a PHP array directly results in a type mismatch error.
- Use the correct node class: for string literals, use PhpParser\Node\Scalar\String_; for integers, use PhpParser\Node\Scalar\LNumber; for variables, use PhpParser\Node\Expr\Variable, etc.
- Importance of use statements: When using PhpParser's various node classes, be sure to add the correct use statement at the top of the file, such as use PhpParser\Node\Expr\ArrayItem; to avoid verbosity in fully qualified class names.
- Version Compatibility: There may be API differences between different versions of the Nikic PhpParser library. The examples in this article are based on newer versions (such as nikic/php-parser 4.x series), please ensure that the library version used by your project is compatible with it.
By following these principles, you can effectively utilize Nikic PhpParser for complex PHP code manipulation and conversion. Understanding the internal structure of the AST is key to successful programmatic code modification.
The above is the detailed content of Use Nikic PhpParser to modify array variables in PHP files. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

ArtGPT
AI image generator for creative art from text prompts.

Stock Market GPT
AI powered investment research for smarter decisions

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Usefilter_var()tovalidateemailsyntaxandcheckdnsrr()toverifydomainMXrecords.Example:$email="user@example.com";if(filter_var($email,FILTER_VALIDATE_EMAIL)&&checkdnsrr(explode('@',$email)[1],'MX')){echo"Validanddeliverableemail&qu

Useunserialize(serialize($obj))fordeepcopyingwhenalldataisserializable;otherwise,implement__clone()tomanuallyduplicatenestedobjectsandavoidsharedreferences.

Usearray_merge()tocombinearrays,overwritingduplicatestringkeysandreindexingnumerickeys;forsimplerconcatenation,especiallyinPHP5.6 ,usethesplatoperator[...$array1,...$array2].

NamespacesinPHPorganizecodeandpreventnamingconflictsbygroupingclasses,interfaces,functions,andconstantsunderaspecificname.2.Defineanamespaceusingthenamespacekeywordatthetopofafile,followedbythenamespacename,suchasApp\Controllers.3.Usetheusekeywordtoi

ToupdateadatabaserecordinPHP,firstconnectusingPDOorMySQLi,thenusepreparedstatementstoexecuteasecureSQLUPDATEquery.Example:$pdo=newPDO("mysql:host=localhost;dbname=your_database",$username,$password);$sql="UPDATEusersSETemail=:emailWHER

The__call()methodistriggeredwhenaninaccessibleorundefinedmethodiscalledonanobject,allowingcustomhandlingbyacceptingthemethodnameandarguments,asshownwhencallingundefinedmethodslikesayHello().2.The__get()methodisinvokedwhenaccessinginaccessibleornon-ex

Usepathinfo($filename,PATHINFO_EXTENSION)togetthefileextension;itreliablyhandlesmultipledotsandedgecases,returningtheextension(e.g.,"pdf")oranemptystringifnoneexists.

Use the ZipArchive class to create a ZIP file. First instantiate and open the target zip, add files with addFile, support custom internal paths, recursive functions can package the entire directory, and finally call close to save to ensure that PHP has write permissions.
