Skip to main content

PHP code refactoring in VSCode

Master PHP code refactoring in VSCode with this guide. Use the free PHP Refactor Tool extension to safely rename symbols, classes, and extract new methods.

· 6 min read
View raw
Christophe
Markdown, WSL and Docker lover ~ Insatiable curious.
Cet article existe aussi en français — lire la version française.

This article is over a year old but was reviewed on July 30, 2026 — the content is still accurate.

PHP code refactoring in VSCode

⚡
TL;DR

This article covers PHP refactoring in VSCode using the free PHP Refactor Tool and PHP Refactoring extensions: renaming a symbol or a class with F2 (which updates every usage across files automatically) and extracting a block of code into a new method, including automatic detection of the local variables that need to become parameters.

Currently, end of February 2024, there aren't many free refactoring extensions for PHP under VSCode. We'll take a look at PHP Refactor Tool and PHP Refactoring.

We'll learn how to rename a symbol, a class and, even better, how to extract a portion of a long method into a new one.

These extensions refactor what you point at. For refactorings suggested — and applied — automatically across a whole codebase, see Rector 1.0.0, my friend, my coach.

Create sample files​

For the demo, please start a Linux shell and run mkdir -p /tmp/refactor && cd $_ to create a folder called refactor in your Linux temporary folder and jump in it.

Please create two php files. The first one will be called index.php and will contain this code:

<?php
namespace Cavo;
require_once('Product.php');
$product = new Product();
$product->setProductName('keyboard');
$product->setProductPrice(125);
printf(
'The name is %s cost %d €'.PHP_EOL,
$product->getProductName(),
$product->getProductPrice()
);

This script creates a Product object, sets its name to 'keyboard' and price to 125, then prints out a formatted message displaying the product's name and price in euros.

The second file Product.php will contain:

<?php
namespace Cavo;
class Product
{
private string $productName = '';
private float $productPrice = 0;
public function __construct(string $name='', float $price=0)
{
$this->setProductName($name);
$this->setProductPrice($price);
}
public function getProductName(): string {
return $this->productName;
}
public function setProductName(string $name): void {
$this->productName = $name;
}
public function getProductPrice(): float {
return $this->productPrice;
}
public function setProductPrice(float $price): void {
$this->productPrice = $price;
}
}

This is a basic Product class that represents an item with a name and price. It uses PHP's typed properties and a constructor to initialize these values, then provides getter and setter methods so other code can read and modify the product's details.

Run the example​

Run docker run -it --rm -v "${PWD}":/project -w /project php:8.2 php index.php to run our example in the console.

You'll get, as expected:

>user@machine: ~/yourproject

Refactoring​

Make sure PHP Refactor Tool is installed. Go to the list of extensions in VSCode (press CTRL-SHIFT-X) and search for PHP Refactor Tool. Install the one of Son Tung PHAM (the author).

Rename a symbol​

The illustration below is showing a sample index.php script using a class defined in Product.php.

Everything is working fine but, yeah, functions are called getProductName and getProductPrice and it's quite redundant: our object is $product so, yes, $product->getProductName() and $product->getProductPrice() can be rewritten to $product->getName() and $product->getPrice(). The smaller, the better.

So, we need to rename our functions.

By opening our Product.php file, we can do it manually but ... don't do this because you'll need to update every single file manually using your Product class and if you forgot just one use, your code will be broken.

The rename feature serves this objective. You just need to select a property like productName as illustrated in the animation, press F2 and rename it.

Let's do it and see how it works:

  1. Open the Product.php file, put the cursor on the word productName in line 7 private string $productName = '';,
  2. Press F2 (or choose Rename Symbol in the Command palette (press CTRL-SHIFT-P)) and type the new name f.i. name (instead of productName),
  3. VSCode will display a small list at the top of the screen, just validate i.e. select Update Getter name and Setter name.
  4. Do the same for productPrice and rename it to price.

The new Product.php file is now:

<?php
namespace Cavo;
class Product
{
private string $name = '';
private float $price = 0;
public function __construct(string $name='', float $price=0)
{
$this->setName($name);
$this->setPrice($price);
}
public function getName(): string {
return $this->name;
}
public function setName(string $name): void {
$this->name = $name;
}
public function getPrice(): float {
return $this->price;
}
public function setPrice(float $price): void {
$this->price = $price;
}
}

This is a Product class that represents a basic product with a name and price. It uses a constructor to initialize these values and provides getter and setter methods to read and modify them. The class enforces type safety by declaring that name must be a string and price must be a float.

But the very cool thing is that index.php has been automatically updated. Open index.php and check:

<?php
namespace Cavo;
require_once('Product.php');
$product = new Product();
$product->setName('keyboard');
$product->setPrice(125);
printf(
'The name is %s cost %d €'.PHP_EOL,
$product->getName(),
$product->getPrice()
);

This script creates a Product object, sets its name to 'keyboard' and price to 125, then prints out those values in a formatted message. It's demonstrating basic object creation and property access in PHP.

By running docker run -it --rm -v "${PWD}":/project -w /project php:8.2 php index.php, it's still working.

You've refactored our code without breaking it. Congratulations!

The same thing in pictures:

Rename a symbol

Rename a class​

For the example, reopen the Product.php file and, on line 5, put the cursor on the word Product. Press F2 and rename to Products (plural form).

As we can expect, the class name has been updated but the filename too. And, once again, if you open the index.php file, you can see that $product = new Product(); has been perfectly changed to $product = new Products();.

Renaming a class

You can also rename from index.php

Locate the $product = new Product(); line in your index.php file. Put the cursor on the Product word, press F2 and rename it. This works too, i.e. the class will also be updated in Products.php (since the file has been renamed too). Nice!

Rename a class

Don't rename the file

Renaming the file from the Explorer won't refactor the code. So, don't go to the Explorer, click on Product.php and rename it. This will not refactor the code. Avoid!

Extract to a new method​

The third very nice method is the Extract method from PHP Refactoring.

Consider the following example (the code isn't running, it's just for the illustration). Create a new file called Pandoc.php with this content:

<?php
namespace Avonture;
class Pandoc
{
public function download(string $filename): void
{
$filename = Sanitize::sanitizeFileName(trim($filename));
if ('' == $filename) {
throw new PandocFileNotSpecified();
}
if (!is_file($this->outputFolder . $filename)) {
throw new PandocFileNotFound($filename);
}
// Make the filename absolute
$filename = $this->outputFolder . ltrim($filename, self::DS);
$this->outputType = pathinfo($filename)['extension'];
$contentType = $this->getContentType()['type'];
header('Content-Type: ' . $contentType);
header('Content-Transfer-Encoding: ' . $this->getContentType()['encoding']);
header('Content-Disposition: attachment; filename="' . basename($filename) . '"');
header('Content-Length: ' . filesize(utf8_decode($filename)));
header('Accept-Ranges: bytes');
header('Pragma: no-cache');
header('Expires: 0');
ob_end_flush();
@readfile(utf8_decode($filename));
}
}

This method handles downloading a file by validating the filename, checking that the file exists, setting appropriate HTTP headers to trigger a browser download, and then reading the file contents to the client. It's the server-side logic that makes a file available for download when a user clicks a download button.

The download function didn't respect the single-responsibility concept. We've made a few initializations and assertions. Can we do better? Yes, we can extract the lines concerning the browser and create a new sendToBrowser function but instead of doing it manually, we'll use the Extract feature.

See the animation below:

Extract to a new method

Did you notice the use of input parameters?

In the lines we're moving, there are variables like contentType and filename that are not part of the new method. These variables are still local in our first, download method.

And, as you can see, during the creation of the new method, these two local variables have been added to the definition of the new function. Nice feature.

Other extensions​

  • 💀 😒 PHP Refactor also exists but the last time it was updated by the author was in 2019, five years ago, and the extract feature isn't working fine; just move along.
  • 💲😒 PHP Tools for Visual Studio Code from DEVSENSE is a freemium addon (refactoring features are only in the paid version). The rename symbol feature is a paid one while it's free with PHP Refactor Tool. Don't install PHP Tools for Visual Studio Code since, then, it'll override PHP Refactor Tool F2 function and will break it. (see my issue Devsense - All-In-One conflicts)

Renaming and extracting methods is one part of keeping PHP code healthy; for automated static analysis and formatting, see the Docker image bundling static analysis tools and formatting poorly formatted PHP code.


Was this article helpful?
Did you try the steps in this article?