6

Lets say I have a method:

public function createFoo(Foo $foo, $isPremiumFoo=false);

In hindsight, it was a little silly to have that $isPremiumFoo flag argument hanging off the end. So we moved it into Foo and now I'd like to remove it from the method signature. But I don't want to do it all at once since this is a public method and is out in the wild being used. I'd like to @deprecate it to alert users to the fact that they should stop using it and then eventually remove it. Since you can't overload methods in PHP, how can I deprecate just that method argument and not the entire method?

Josh Johnson
  • 10,729
  • 12
  • 60
  • 83
  • If you're able to modify the contents of `createFoo`, just prepend it with `func_num_args` check (I assume you're talking about deprecating both `createFoo($foo, true)` and `createFoo($foo, false)` calls; otherwise it'd be trivial just to check for `$isPremiumFoo === false`). – raina77ow Nov 18 '14 at 22:23
  • I'm sorry. I meant, how can I mark the method argument as `@deprecated` without marking the entire method as such. – Josh Johnson Nov 18 '14 at 22:29
  • @JoshJohnson just remove it from the signature. If someone provides 2 arguments, take it in mind. If only one - use that, which a property of Foo. – Royal Bg Nov 18 '14 at 22:32

4 Answers4

8

If you have PhpStorm 2020.3 or later you can use #[Deprecated] attribute. It is parsed as comment for PHP versions < 8, attribute for >=8 versions:

Usage of deprecated parameter attribute

gskema
  • 3,141
  • 2
  • 20
  • 39
7

You could do something like this

class Foo {

}
class Bar {
    public function createFoo(Foo $foo, $isPremiumFoo=false) {
        if (count(func_get_args()) > 1) {
            $warn = "isPremiumFoo is deprecated and will be removed 
                     in a future release"; 
            trigger_error($warn, E_USER_NOTICE);    
        }
        // continue with the implementation
    }
}

$foo = new Foo();
$bar = new Bar();

$bar->createFoo($foo);         // wont trigger the notice
$bar->createFoo($foo, true);   // will trigger the notice
$bar->createFoo($foo, false);  // will trigger the notice
robbmj
  • 16,085
  • 8
  • 38
  • 63
  • Thanks! I'm accepting this because it gets the job done and at least warns at run time about it (bonus is that log aggregators can report on usage) but am still looking for a way to have common editors (PHPStorm, Vi, etc) alert the user while they're typing as they do for when a method is `@deprecated`. – Josh Johnson Jun 01 '17 at 19:50
  • 2
    Anyone looking to use this method note that E_USER_DEPRECATED was added PHP 5.3 and would be more fitting for this purpose. – h00ligan Aug 03 '18 at 07:23
2

I've done the same thing. The approach we use in our team is simply to update the docblock.

Then in the IDE's, when someone gets a popup they can clearly see that it was deprecated and we don't use it. As time progresses, we finally remove it altogether.

Example:

/**
 * Create Foo
 *    
 * @param Foo Description
 * @param bool Deprecated, use Foo->setIsPremium(true|false)
 *
 * @return Bar
 */
public function createFoo(Foo $foo, $isPremiumFoo=false);
Dharman
  • 30,962
  • 25
  • 85
  • 135
caseyw
  • 105
  • 7
  • For the new users - yes. But the existing ones may not even realize that change. Shouldn't it be like PHP deprecations. Your site runs e.g. with mysql_* functions. You update to PHP 5.5 and all of your logs are filled with notices for deprecated method. – Royal Bg Nov 18 '14 at 22:52
  • It totally could. The situation we're in is likely a bit more unique since we're dealing with mostly new hires in a rapidly changing code base. Thanks for the comment, and I may consider throwing those warnings here in the near term. – caseyw Nov 18 '14 at 23:15
0
<?php
class Foo
{
    private $isPremium = false;

    public function setPremium($premium)
    {
        $this->isPremium = $premium;
    }

    public function isPremium() 
    {
        return $this->isPremium;
    }
}

function createFoo(Foo $foo)
{
    if (func_num_args() > 1) {
        $isPremium = func_get_args()[1];
        $foo->setPremium($isPremium);
    }

    return $foo;
}

$foo = new Foo();
var_dump(createFoo($foo)); // false (because default value is false in the class)
$foo->setPremium(true);
var_dump(createFoo($foo)); // true (the new way - you can manipulate it as an object property.)
var_dump(createFoo($foo, false)); // false (even thought you have manipulated it, it's backwards compatibility for users who are using the second param)
var_dump(createFoo($foo, true)); // true (again backward compatibility)

The explanation is in the code comments. Basically, there isn't anything that stops you to call a function with more params than it recieves. So you can safely remove it from the signature and check for it in the function body.

Using that logic, you can show the users some kind of warning, if a second parameter is provided. Your new users, using the new API may not even be aware that a second parameter ever existed.

Royal Bg
  • 6,988
  • 1
  • 18
  • 24