Insphpect

This tool is currently proof-of-concept. Your feedback and evaluation is valuable in helping to improve it and ensure its reports are meaninful.

Please click here to complete a short survey to tell us what you think. It should take less than 5 minutes and help further this research project!

GuzzleHttp\Middleware

Detected issues

Issue Method Line number
Use of static methods cookies 24
Use of static methods httpErrors 52
Use of static methods history 81
Use of static methods null 126
Use of static methods redirect 147
Use of static methods null 169
Use of static methods string 186
Use of static methods prepareBody 213
Use of static methods mapRequest 227
Use of static methods mapResponse 243

Code

Click highlighted lines for details

<?phpnamespace GuzzleHttp;use GuzzleHttp\Cookie\CookieJarInterface;use GuzzleHttp\Exception\RequestException;use GuzzleHttp\Promise\PromiseInterface;use Psr\Http\Message\RequestInterface;use Psr\Http\Message\ResponseInterface;use Psr\Log\LoggerInterface;/** * Functions used to create and wrap handlers with handler middleware. */final class Middleware{    /**     * Middleware that adds cookies to requests.     *     * The options array must be set to a CookieJarInterface in order to use     * cookies. This is typically handled for you by a client.     *     * @return callable Returns a function that accepts the next handler.     */

Static methods

Summary of issues

  • Tight Coupling
  • Hidden dependencies
  • Global state (if also using static variables)

Tight Coupling

Use of static methods always reduces flexibility by introducing tight coupling[1]. A static method tightly couples the calling code to the specific class the method exists in.

 
function totalAbs(double valuedouble value2) {
    return 
abs(value) + abs(value2);
}

Here, the method totalAbs has a dependency on the Math class and the .abs() method will always be called. Although for testing purposes this may not be a problem, the coupling reduces flexibility because the total method can only work with doubles/integers, as that's all the Math.abs() function can use. Although type coercion will allow the use of any primitive numeric type, these types have limitations. It's impossible to use another class such as BigInteger or a class for dealing with greater precision decimals or even alternative numbering systems such as Roman numerals.

The totalAbs function takes two doubles and converts them to their absolute values before adding them. This is inflexible because it only works with doubles. It's tied to doubles because that's what the Math.abs() static method requires. If, instead, using OOP an interface was created to handle any number that had this method:

 interface Numeric {
    public function 
abs(): Numeric;
}

It would then be possible to rewrite the totalAbs method to work with any kind of number:

 function totalAbs(Numeric valueNumeric value): Numeric {
    return 
value.abs() + value2.abs();
}

By removing the static method and using an instance method in its place the totalAbs method is now agnostic about the type of number it is dealing with. It could be called with any of the following (assuming they implement the Numeric interface)

 
totalAbs(new Integer(4), new Integer(-53));

totalAbs(new Double(34.4), new Integer(-2));

totalAbs(new BigInteger('123445454564765739878989343225778'), new Integer(2343));

totalAbs(new RomanNumeral('VII'), new RomanNumeral('CXV'));

Making the method reusable in a way that it wasn't when static methods were being used. By changing the static methods to instance methods, flexibility has been enhanced as the method can be used with any numeric type, not just numeric types that are supported by the Math.abs() method.

Broken encapsulation

Static methods also break encapsulation. Encapsulation is defined by Rogers[2] as:

the bundling of data with the methods that operate on that data

By passing the numeric value into the abs method, the data being operated on is being separated from the methods that operate on it, breaking encapsulation. Instead using num.abs() the data is encapsulated in the num instance and its type is not visible or relevant to the outside world. abs() will work on the data and work regardless of num's type, providing it implements the abs method.

This is a simple example, but applies to all static methods. Use of polymorphic instance methods that work on encapsulated data will always be more flexible than static method calls which can only ever deal with specific pre-defined types.

Further reading

Exceptions

The only exception to this rule is when a static method is used for object creation in place of the new keyword[3]. This is because the new keyword is already a static call. However, even here a non-static factory is often preferable for testing purposes[4][5].

References

  1. Popov, N. (2014) Don't be STUPID: GRASP SOLID! [online]. Available from: https://nikic.github.io/2011/12/27/Dont-be-STUPID-GRASP-SOLID.html
  2. Rogers, P. (2001) Encapsulation is not information hiding [online]. Available from: http://www.javaworld.com/article/2075271/core-java/encapsulation-is-not-information-hiding.html
  3. Sonmez, J. (2010) Static Methods Will Shock You [online]. Available from: http://simpleprogrammer.com/2010/01/29/static-methods-will-shock-you/
  4. Hevery, M. (2008) Static Methods are Death to Testability [online]. Available from: http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/
  5. Butler, T. (2013) Are Static Methods/Variables bad practice? [online]. Available from: https://r.je/static-methods-bad-practice.html
{ return function (callable $handler): callable { return function ($request, array $options) use ($handler) { if (empty($options['cookies'])) { return $handler($request, $options); } elseif (!($options['cookies'] instanceof CookieJarInterface)) { throw new \InvalidArgumentException('cookies must be an instance of GuzzleHttp\Cookie\CookieJarInterface'); } $cookieJar = $options['cookies']; $request = $cookieJar->withCookieHeader($request); return $handler($request, $options) ->then( function (ResponseInterface $response) use ($cookieJar, $request): ResponseInterface { $cookieJar->extractCookies($request, $response); return $response; } ); }; }; } /** * Middleware that throws exceptions for 4xx or 5xx responses when the * "http_error" request option is set to true. * * @return callable Returns a function that accepts the next handler. */

Static methods

Summary of issues

  • Tight Coupling
  • Hidden dependencies
  • Global state (if also using static variables)

Tight Coupling

Use of static methods always reduces flexibility by introducing tight coupling[1]. A static method tightly couples the calling code to the specific class the method exists in.

 
function totalAbs(double valuedouble value2) {
    return 
abs(value) + abs(value2);
}

Here, the method totalAbs has a dependency on the Math class and the .abs() method will always be called. Although for testing purposes this may not be a problem, the coupling reduces flexibility because the total method can only work with doubles/integers, as that's all the Math.abs() function can use. Although type coercion will allow the use of any primitive numeric type, these types have limitations. It's impossible to use another class such as BigInteger or a class for dealing with greater precision decimals or even alternative numbering systems such as Roman numerals.

The totalAbs function takes two doubles and converts them to their absolute values before adding them. This is inflexible because it only works with doubles. It's tied to doubles because that's what the Math.abs() static method requires. If, instead, using OOP an interface was created to handle any number that had this method:

 interface Numeric {
    public function 
abs(): Numeric;
}

It would then be possible to rewrite the totalAbs method to work with any kind of number:

 function totalAbs(Numeric valueNumeric value): Numeric {
    return 
value.abs() + value2.abs();
}

By removing the static method and using an instance method in its place the totalAbs method is now agnostic about the type of number it is dealing with. It could be called with any of the following (assuming they implement the Numeric interface)

 
totalAbs(new Integer(4), new Integer(-53));

totalAbs(new Double(34.4), new Integer(-2));

totalAbs(new BigInteger('123445454564765739878989343225778'), new Integer(2343));

totalAbs(new RomanNumeral('VII'), new RomanNumeral('CXV'));

Making the method reusable in a way that it wasn't when static methods were being used. By changing the static methods to instance methods, flexibility has been enhanced as the method can be used with any numeric type, not just numeric types that are supported by the Math.abs() method.

Broken encapsulation

Static methods also break encapsulation. Encapsulation is defined by Rogers[2] as:

the bundling of data with the methods that operate on that data

By passing the numeric value into the abs method, the data being operated on is being separated from the methods that operate on it, breaking encapsulation. Instead using num.abs() the data is encapsulated in the num instance and its type is not visible or relevant to the outside world. abs() will work on the data and work regardless of num's type, providing it implements the abs method.

This is a simple example, but applies to all static methods. Use of polymorphic instance methods that work on encapsulated data will always be more flexible than static method calls which can only ever deal with specific pre-defined types.

Further reading

Exceptions

The only exception to this rule is when a static method is used for object creation in place of the new keyword[3]. This is because the new keyword is already a static call. However, even here a non-static factory is often preferable for testing purposes[4][5].

References

  1. Popov, N. (2014) Don't be STUPID: GRASP SOLID! [online]. Available from: https://nikic.github.io/2011/12/27/Dont-be-STUPID-GRASP-SOLID.html
  2. Rogers, P. (2001) Encapsulation is not information hiding [online]. Available from: http://www.javaworld.com/article/2075271/core-java/encapsulation-is-not-information-hiding.html
  3. Sonmez, J. (2010) Static Methods Will Shock You [online]. Available from: http://simpleprogrammer.com/2010/01/29/static-methods-will-shock-you/
  4. Hevery, M. (2008) Static Methods are Death to Testability [online]. Available from: http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/
  5. Butler, T. (2013) Are Static Methods/Variables bad practice? [online]. Available from: https://r.je/static-methods-bad-practice.html
{ return function (callable $handler): callable { return function ($request, array $options) use ($handler) { if (empty($options['http_errors'])) { return $handler($request, $options); } return $handler($request, $options)->then( function (ResponseInterface $response) use ($request) { $code = $response->getStatusCode(); if ($code < 400) { return $response; } throw RequestException::create($request, $response); } ); }; }; } /** * Middleware that pushes history data to an ArrayAccess container. * * @param array|\ArrayAccess $container Container to hold the history (by reference). * * @return callable Returns a function that accepts the next handler. * * @throws \InvalidArgumentException if container is not an array or ArrayAccess. */

Static methods

Summary of issues

  • Tight Coupling
  • Hidden dependencies
  • Global state (if also using static variables)

Tight Coupling

Use of static methods always reduces flexibility by introducing tight coupling[1]. A static method tightly couples the calling code to the specific class the method exists in.

 
function totalAbs(double valuedouble value2) {
    return 
abs(value) + abs(value2);
}

Here, the method totalAbs has a dependency on the Math class and the .abs() method will always be called. Although for testing purposes this may not be a problem, the coupling reduces flexibility because the total method can only work with doubles/integers, as that's all the Math.abs() function can use. Although type coercion will allow the use of any primitive numeric type, these types have limitations. It's impossible to use another class such as BigInteger or a class for dealing with greater precision decimals or even alternative numbering systems such as Roman numerals.

The totalAbs function takes two doubles and converts them to their absolute values before adding them. This is inflexible because it only works with doubles. It's tied to doubles because that's what the Math.abs() static method requires. If, instead, using OOP an interface was created to handle any number that had this method:

 interface Numeric {
    public function 
abs(): Numeric;
}

It would then be possible to rewrite the totalAbs method to work with any kind of number:

 function totalAbs(Numeric valueNumeric value): Numeric {
    return 
value.abs() + value2.abs();
}

By removing the static method and using an instance method in its place the totalAbs method is now agnostic about the type of number it is dealing with. It could be called with any of the following (assuming they implement the Numeric interface)

 
totalAbs(new Integer(4), new Integer(-53));

totalAbs(new Double(34.4), new Integer(-2));

totalAbs(new BigInteger('123445454564765739878989343225778'), new Integer(2343));

totalAbs(new RomanNumeral('VII'), new RomanNumeral('CXV'));

Making the method reusable in a way that it wasn't when static methods were being used. By changing the static methods to instance methods, flexibility has been enhanced as the method can be used with any numeric type, not just numeric types that are supported by the Math.abs() method.

Broken encapsulation

Static methods also break encapsulation. Encapsulation is defined by Rogers[2] as:

the bundling of data with the methods that operate on that data

By passing the numeric value into the abs method, the data being operated on is being separated from the methods that operate on it, breaking encapsulation. Instead using num.abs() the data is encapsulated in the num instance and its type is not visible or relevant to the outside world. abs() will work on the data and work regardless of num's type, providing it implements the abs method.

This is a simple example, but applies to all static methods. Use of polymorphic instance methods that work on encapsulated data will always be more flexible than static method calls which can only ever deal with specific pre-defined types.

Further reading

Exceptions

The only exception to this rule is when a static method is used for object creation in place of the new keyword[3]. This is because the new keyword is already a static call. However, even here a non-static factory is often preferable for testing purposes[4][5].

References

  1. Popov, N. (2014) Don't be STUPID: GRASP SOLID! [online]. Available from: https://nikic.github.io/2011/12/27/Dont-be-STUPID-GRASP-SOLID.html
  2. Rogers, P. (2001) Encapsulation is not information hiding [online]. Available from: http://www.javaworld.com/article/2075271/core-java/encapsulation-is-not-information-hiding.html
  3. Sonmez, J. (2010) Static Methods Will Shock You [online]. Available from: http://simpleprogrammer.com/2010/01/29/static-methods-will-shock-you/
  4. Hevery, M. (2008) Static Methods are Death to Testability [online]. Available from: http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/
  5. Butler, T. (2013) Are Static Methods/Variables bad practice? [online]. Available from: https://r.je/static-methods-bad-practice.html
{ if (!\is_array($container) && !$container instanceof \ArrayAccess) { throw new \InvalidArgumentException('history container must be an array or object implementing ArrayAccess'); } return function (callable $handler) use (&$container): callable { return function (RequestInterface $request, array $options) use ($handler, &$container) { return $handler($request, $options)->then( function ($value) use ($request, &$container, $options) { $container[] = [ 'request' => $request, 'response' => $value, 'error' => null, 'options' => $options ]; return $value; }, function ($reason) use ($request, &$container, $options) { $container[] = [ 'request' => $request, 'response' => null, 'error' => $reason, 'options' => $options ]; return \GuzzleHttp\Promise\rejection_for($reason); } ); }; }; } /** * Middleware that invokes a callback before and after sending a request. * * The provided listener cannot modify or alter the response. It simply * "taps" into the chain to be notified before returning the promise. The * before listener accepts a request and options array, and the after * listener accepts a request, options array, and response promise. * * @param callable $before Function to invoke before forwarding the request. * @param callable $after Function invoked after forwarding. * * @return callable Returns a function that accepts the next handler. */

Static methods

Summary of issues

  • Tight Coupling
  • Hidden dependencies
  • Global state (if also using static variables)

Tight Coupling

Use of static methods always reduces flexibility by introducing tight coupling[1]. A static method tightly couples the calling code to the specific class the method exists in.

 
function totalAbs(double valuedouble value2) {
    return 
abs(value) + abs(value2);
}

Here, the method totalAbs has a dependency on the Math class and the .abs() method will always be called. Although for testing purposes this may not be a problem, the coupling reduces flexibility because the total method can only work with doubles/integers, as that's all the Math.abs() function can use. Although type coercion will allow the use of any primitive numeric type, these types have limitations. It's impossible to use another class such as BigInteger or a class for dealing with greater precision decimals or even alternative numbering systems such as Roman numerals.

The totalAbs function takes two doubles and converts them to their absolute values before adding them. This is inflexible because it only works with doubles. It's tied to doubles because that's what the Math.abs() static method requires. If, instead, using OOP an interface was created to handle any number that had this method:

 interface Numeric {
    public function 
abs(): Numeric;
}

It would then be possible to rewrite the totalAbs method to work with any kind of number:

 function totalAbs(Numeric valueNumeric value): Numeric {
    return 
value.abs() + value2.abs();
}

By removing the static method and using an instance method in its place the totalAbs method is now agnostic about the type of number it is dealing with. It could be called with any of the following (assuming they implement the Numeric interface)

 
totalAbs(new Integer(4), new Integer(-53));

totalAbs(new Double(34.4), new Integer(-2));

totalAbs(new BigInteger('123445454564765739878989343225778'), new Integer(2343));

totalAbs(new RomanNumeral('VII'), new RomanNumeral('CXV'));

Making the method reusable in a way that it wasn't when static methods were being used. By changing the static methods to instance methods, flexibility has been enhanced as the method can be used with any numeric type, not just numeric types that are supported by the Math.abs() method.

Broken encapsulation

Static methods also break encapsulation. Encapsulation is defined by Rogers[2] as:

the bundling of data with the methods that operate on that data

By passing the numeric value into the abs method, the data being operated on is being separated from the methods that operate on it, breaking encapsulation. Instead using num.abs() the data is encapsulated in the num instance and its type is not visible or relevant to the outside world. abs() will work on the data and work regardless of num's type, providing it implements the abs method.

This is a simple example, but applies to all static methods. Use of polymorphic instance methods that work on encapsulated data will always be more flexible than static method calls which can only ever deal with specific pre-defined types.

Further reading

Exceptions

The only exception to this rule is when a static method is used for object creation in place of the new keyword[3]. This is because the new keyword is already a static call. However, even here a non-static factory is often preferable for testing purposes[4][5].

References

  1. Popov, N. (2014) Don't be STUPID: GRASP SOLID! [online]. Available from: https://nikic.github.io/2011/12/27/Dont-be-STUPID-GRASP-SOLID.html
  2. Rogers, P. (2001) Encapsulation is not information hiding [online]. Available from: http://www.javaworld.com/article/2075271/core-java/encapsulation-is-not-information-hiding.html
  3. Sonmez, J. (2010) Static Methods Will Shock You [online]. Available from: http://simpleprogrammer.com/2010/01/29/static-methods-will-shock-you/
  4. Hevery, M. (2008) Static Methods are Death to Testability [online]. Available from: http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/
  5. Butler, T. (2013) Are Static Methods/Variables bad practice? [online]. Available from: https://r.je/static-methods-bad-practice.html
{ return function (callable $handler) use ($before, $after): callable { return function (RequestInterface $request, array $options) use ($handler, $before, $after) { if ($before) { $before($request, $options); } $response = $handler($request, $options); if ($after) { $after($request, $options, $response); } return $response; }; }; } /** * Middleware that handles request redirects. * * @return callable Returns a function that accepts the next handler. */

Static methods

Summary of issues

  • Tight Coupling
  • Hidden dependencies
  • Global state (if also using static variables)

Tight Coupling

Use of static methods always reduces flexibility by introducing tight coupling[1]. A static method tightly couples the calling code to the specific class the method exists in.

 
function totalAbs(double valuedouble value2) {
    return 
abs(value) + abs(value2);
}

Here, the method totalAbs has a dependency on the Math class and the .abs() method will always be called. Although for testing purposes this may not be a problem, the coupling reduces flexibility because the total method can only work with doubles/integers, as that's all the Math.abs() function can use. Although type coercion will allow the use of any primitive numeric type, these types have limitations. It's impossible to use another class such as BigInteger or a class for dealing with greater precision decimals or even alternative numbering systems such as Roman numerals.

The totalAbs function takes two doubles and converts them to their absolute values before adding them. This is inflexible because it only works with doubles. It's tied to doubles because that's what the Math.abs() static method requires. If, instead, using OOP an interface was created to handle any number that had this method:

 interface Numeric {
    public function 
abs(): Numeric;
}

It would then be possible to rewrite the totalAbs method to work with any kind of number:

 function totalAbs(Numeric valueNumeric value): Numeric {
    return 
value.abs() + value2.abs();
}

By removing the static method and using an instance method in its place the totalAbs method is now agnostic about the type of number it is dealing with. It could be called with any of the following (assuming they implement the Numeric interface)

 
totalAbs(new Integer(4), new Integer(-53));

totalAbs(new Double(34.4), new Integer(-2));

totalAbs(new BigInteger('123445454564765739878989343225778'), new Integer(2343));

totalAbs(new RomanNumeral('VII'), new RomanNumeral('CXV'));

Making the method reusable in a way that it wasn't when static methods were being used. By changing the static methods to instance methods, flexibility has been enhanced as the method can be used with any numeric type, not just numeric types that are supported by the Math.abs() method.

Broken encapsulation

Static methods also break encapsulation. Encapsulation is defined by Rogers[2] as:

the bundling of data with the methods that operate on that data

By passing the numeric value into the abs method, the data being operated on is being separated from the methods that operate on it, breaking encapsulation. Instead using num.abs() the data is encapsulated in the num instance and its type is not visible or relevant to the outside world. abs() will work on the data and work regardless of num's type, providing it implements the abs method.

This is a simple example, but applies to all static methods. Use of polymorphic instance methods that work on encapsulated data will always be more flexible than static method calls which can only ever deal with specific pre-defined types.

Further reading

Exceptions

The only exception to this rule is when a static method is used for object creation in place of the new keyword[3]. This is because the new keyword is already a static call. However, even here a non-static factory is often preferable for testing purposes[4][5].

References

  1. Popov, N. (2014) Don't be STUPID: GRASP SOLID! [online]. Available from: https://nikic.github.io/2011/12/27/Dont-be-STUPID-GRASP-SOLID.html
  2. Rogers, P. (2001) Encapsulation is not information hiding [online]. Available from: http://www.javaworld.com/article/2075271/core-java/encapsulation-is-not-information-hiding.html
  3. Sonmez, J. (2010) Static Methods Will Shock You [online]. Available from: http://simpleprogrammer.com/2010/01/29/static-methods-will-shock-you/
  4. Hevery, M. (2008) Static Methods are Death to Testability [online]. Available from: http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/
  5. Butler, T. (2013) Are Static Methods/Variables bad practice? [online]. Available from: https://r.je/static-methods-bad-practice.html
{ return function (callable $handler): RedirectMiddleware { return new RedirectMiddleware($handler); }; } /** * Middleware that retries requests based on the boolean result of * invoking the provided "decider" function. * * If no delay function is provided, a simple implementation of exponential * backoff will be utilized. * * @param callable $decider Function that accepts the number of retries, * a request, [response], and [exception] and * returns true if the request is to be retried. * @param callable $delay Function that accepts the number of retries and * returns the number of milliseconds to delay. * * @return callable Returns a function that accepts the next handler. */

Static methods

Summary of issues

  • Tight Coupling
  • Hidden dependencies
  • Global state (if also using static variables)

Tight Coupling

Use of static methods always reduces flexibility by introducing tight coupling[1]. A static method tightly couples the calling code to the specific class the method exists in.

 
function totalAbs(double valuedouble value2) {
    return 
abs(value) + abs(value2);
}

Here, the method totalAbs has a dependency on the Math class and the .abs() method will always be called. Although for testing purposes this may not be a problem, the coupling reduces flexibility because the total method can only work with doubles/integers, as that's all the Math.abs() function can use. Although type coercion will allow the use of any primitive numeric type, these types have limitations. It's impossible to use another class such as BigInteger or a class for dealing with greater precision decimals or even alternative numbering systems such as Roman numerals.

The totalAbs function takes two doubles and converts them to their absolute values before adding them. This is inflexible because it only works with doubles. It's tied to doubles because that's what the Math.abs() static method requires. If, instead, using OOP an interface was created to handle any number that had this method:

 interface Numeric {
    public function 
abs(): Numeric;
}

It would then be possible to rewrite the totalAbs method to work with any kind of number:

 function totalAbs(Numeric valueNumeric value): Numeric {
    return 
value.abs() + value2.abs();
}

By removing the static method and using an instance method in its place the totalAbs method is now agnostic about the type of number it is dealing with. It could be called with any of the following (assuming they implement the Numeric interface)

 
totalAbs(new Integer(4), new Integer(-53));

totalAbs(new Double(34.4), new Integer(-2));

totalAbs(new BigInteger('123445454564765739878989343225778'), new Integer(2343));

totalAbs(new RomanNumeral('VII'), new RomanNumeral('CXV'));

Making the method reusable in a way that it wasn't when static methods were being used. By changing the static methods to instance methods, flexibility has been enhanced as the method can be used with any numeric type, not just numeric types that are supported by the Math.abs() method.

Broken encapsulation

Static methods also break encapsulation. Encapsulation is defined by Rogers[2] as:

the bundling of data with the methods that operate on that data

By passing the numeric value into the abs method, the data being operated on is being separated from the methods that operate on it, breaking encapsulation. Instead using num.abs() the data is encapsulated in the num instance and its type is not visible or relevant to the outside world. abs() will work on the data and work regardless of num's type, providing it implements the abs method.

This is a simple example, but applies to all static methods. Use of polymorphic instance methods that work on encapsulated data will always be more flexible than static method calls which can only ever deal with specific pre-defined types.

Further reading

Exceptions

The only exception to this rule is when a static method is used for object creation in place of the new keyword[3]. This is because the new keyword is already a static call. However, even here a non-static factory is often preferable for testing purposes[4][5].

References

  1. Popov, N. (2014) Don't be STUPID: GRASP SOLID! [online]. Available from: https://nikic.github.io/2011/12/27/Dont-be-STUPID-GRASP-SOLID.html
  2. Rogers, P. (2001) Encapsulation is not information hiding [online]. Available from: http://www.javaworld.com/article/2075271/core-java/encapsulation-is-not-information-hiding.html
  3. Sonmez, J. (2010) Static Methods Will Shock You [online]. Available from: http://simpleprogrammer.com/2010/01/29/static-methods-will-shock-you/
  4. Hevery, M. (2008) Static Methods are Death to Testability [online]. Available from: http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/
  5. Butler, T. (2013) Are Static Methods/Variables bad practice? [online]. Available from: https://r.je/static-methods-bad-practice.html
{ return function (callable $handler) use ($decider, $delay): RetryMiddleware { return new RetryMiddleware($decider, $handler, $delay); }; } /** * Middleware that logs requests, responses, and errors using a message * formatter. * * @param LoggerInterface $logger Logs messages. * @param MessageFormatter $formatter Formatter used to create message strings. * @param string $logLevel Level at which to log requests. * * @return callable Returns a function that accepts the next handler. */

Static methods

Summary of issues

  • Tight Coupling
  • Hidden dependencies
  • Global state (if also using static variables)

Tight Coupling

Use of static methods always reduces flexibility by introducing tight coupling[1]. A static method tightly couples the calling code to the specific class the method exists in.

 
function totalAbs(double valuedouble value2) {
    return 
abs(value) + abs(value2);
}

Here, the method totalAbs has a dependency on the Math class and the .abs() method will always be called. Although for testing purposes this may not be a problem, the coupling reduces flexibility because the total method can only work with doubles/integers, as that's all the Math.abs() function can use. Although type coercion will allow the use of any primitive numeric type, these types have limitations. It's impossible to use another class such as BigInteger or a class for dealing with greater precision decimals or even alternative numbering systems such as Roman numerals.

The totalAbs function takes two doubles and converts them to their absolute values before adding them. This is inflexible because it only works with doubles. It's tied to doubles because that's what the Math.abs() static method requires. If, instead, using OOP an interface was created to handle any number that had this method:

 interface Numeric {
    public function 
abs(): Numeric;
}

It would then be possible to rewrite the totalAbs method to work with any kind of number:

 function totalAbs(Numeric valueNumeric value): Numeric {
    return 
value.abs() + value2.abs();
}

By removing the static method and using an instance method in its place the totalAbs method is now agnostic about the type of number it is dealing with. It could be called with any of the following (assuming they implement the Numeric interface)

 
totalAbs(new Integer(4), new Integer(-53));

totalAbs(new Double(34.4), new Integer(-2));

totalAbs(new BigInteger('123445454564765739878989343225778'), new Integer(2343));

totalAbs(new RomanNumeral('VII'), new RomanNumeral('CXV'));

Making the method reusable in a way that it wasn't when static methods were being used. By changing the static methods to instance methods, flexibility has been enhanced as the method can be used with any numeric type, not just numeric types that are supported by the Math.abs() method.

Broken encapsulation

Static methods also break encapsulation. Encapsulation is defined by Rogers[2] as:

the bundling of data with the methods that operate on that data

By passing the numeric value into the abs method, the data being operated on is being separated from the methods that operate on it, breaking encapsulation. Instead using num.abs() the data is encapsulated in the num instance and its type is not visible or relevant to the outside world. abs() will work on the data and work regardless of num's type, providing it implements the abs method.

This is a simple example, but applies to all static methods. Use of polymorphic instance methods that work on encapsulated data will always be more flexible than static method calls which can only ever deal with specific pre-defined types.

Further reading

Exceptions

The only exception to this rule is when a static method is used for object creation in place of the new keyword[3]. This is because the new keyword is already a static call. However, even here a non-static factory is often preferable for testing purposes[4][5].

References

  1. Popov, N. (2014) Don't be STUPID: GRASP SOLID! [online]. Available from: https://nikic.github.io/2011/12/27/Dont-be-STUPID-GRASP-SOLID.html
  2. Rogers, P. (2001) Encapsulation is not information hiding [online]. Available from: http://www.javaworld.com/article/2075271/core-java/encapsulation-is-not-information-hiding.html
  3. Sonmez, J. (2010) Static Methods Will Shock You [online]. Available from: http://simpleprogrammer.com/2010/01/29/static-methods-will-shock-you/
  4. Hevery, M. (2008) Static Methods are Death to Testability [online]. Available from: http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/
  5. Butler, T. (2013) Are Static Methods/Variables bad practice? [online]. Available from: https://r.je/static-methods-bad-practice.html
{ return function (callable $handler) use ($logger, $formatter, $logLevel): callable { return function (RequestInterface $request, array $options = []) use ($handler, $logger, $formatter, $logLevel) { return $handler($request, $options)->then( function ($response) use ($logger, $request, $formatter, $logLevel): ResponseInterface { $message = $formatter->format($request, $response); $logger->log($logLevel, $message); return $response; }, function ($reason) use ($logger, $request, $formatter): PromiseInterface { $response = $reason instanceof RequestException ? $reason->getResponse() : null; $message = $formatter->format($request, $response, \GuzzleHttp\Promise\exception_for($reason)); $logger->notice($message); return \GuzzleHttp\Promise\rejection_for($reason); } ); }; }; } /** * This middleware adds a default content-type if possible, a default * content-length or transfer-encoding header, and the expect header. */

Static methods

Summary of issues

  • Tight Coupling
  • Hidden dependencies
  • Global state (if also using static variables)

Tight Coupling

Use of static methods always reduces flexibility by introducing tight coupling[1]. A static method tightly couples the calling code to the specific class the method exists in.

 
function totalAbs(double valuedouble value2) {
    return 
abs(value) + abs(value2);
}

Here, the method totalAbs has a dependency on the Math class and the .abs() method will always be called. Although for testing purposes this may not be a problem, the coupling reduces flexibility because the total method can only work with doubles/integers, as that's all the Math.abs() function can use. Although type coercion will allow the use of any primitive numeric type, these types have limitations. It's impossible to use another class such as BigInteger or a class for dealing with greater precision decimals or even alternative numbering systems such as Roman numerals.

The totalAbs function takes two doubles and converts them to their absolute values before adding them. This is inflexible because it only works with doubles. It's tied to doubles because that's what the Math.abs() static method requires. If, instead, using OOP an interface was created to handle any number that had this method:

 interface Numeric {
    public function 
abs(): Numeric;
}

It would then be possible to rewrite the totalAbs method to work with any kind of number:

 function totalAbs(Numeric valueNumeric value): Numeric {
    return 
value.abs() + value2.abs();
}

By removing the static method and using an instance method in its place the totalAbs method is now agnostic about the type of number it is dealing with. It could be called with any of the following (assuming they implement the Numeric interface)

 
totalAbs(new Integer(4), new Integer(-53));

totalAbs(new Double(34.4), new Integer(-2));

totalAbs(new BigInteger('123445454564765739878989343225778'), new Integer(2343));

totalAbs(new RomanNumeral('VII'), new RomanNumeral('CXV'));

Making the method reusable in a way that it wasn't when static methods were being used. By changing the static methods to instance methods, flexibility has been enhanced as the method can be used with any numeric type, not just numeric types that are supported by the Math.abs() method.

Broken encapsulation

Static methods also break encapsulation. Encapsulation is defined by Rogers[2] as:

the bundling of data with the methods that operate on that data

By passing the numeric value into the abs method, the data being operated on is being separated from the methods that operate on it, breaking encapsulation. Instead using num.abs() the data is encapsulated in the num instance and its type is not visible or relevant to the outside world. abs() will work on the data and work regardless of num's type, providing it implements the abs method.

This is a simple example, but applies to all static methods. Use of polymorphic instance methods that work on encapsulated data will always be more flexible than static method calls which can only ever deal with specific pre-defined types.

Further reading

Exceptions

The only exception to this rule is when a static method is used for object creation in place of the new keyword[3]. This is because the new keyword is already a static call. However, even here a non-static factory is often preferable for testing purposes[4][5].

References

  1. Popov, N. (2014) Don't be STUPID: GRASP SOLID! [online]. Available from: https://nikic.github.io/2011/12/27/Dont-be-STUPID-GRASP-SOLID.html
  2. Rogers, P. (2001) Encapsulation is not information hiding [online]. Available from: http://www.javaworld.com/article/2075271/core-java/encapsulation-is-not-information-hiding.html
  3. Sonmez, J. (2010) Static Methods Will Shock You [online]. Available from: http://simpleprogrammer.com/2010/01/29/static-methods-will-shock-you/
  4. Hevery, M. (2008) Static Methods are Death to Testability [online]. Available from: http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/
  5. Butler, T. (2013) Are Static Methods/Variables bad practice? [online]. Available from: https://r.je/static-methods-bad-practice.html
{ return function (callable $handler): PrepareBodyMiddleware { return new PrepareBodyMiddleware($handler); }; } /** * Middleware that applies a map function to the request before passing to * the next handler. * * @param callable $fn Function that accepts a RequestInterface and returns * a RequestInterface. */

Static methods

Summary of issues

  • Tight Coupling
  • Hidden dependencies
  • Global state (if also using static variables)

Tight Coupling

Use of static methods always reduces flexibility by introducing tight coupling[1]. A static method tightly couples the calling code to the specific class the method exists in.

 
function totalAbs(double valuedouble value2) {
    return 
abs(value) + abs(value2);
}

Here, the method totalAbs has a dependency on the Math class and the .abs() method will always be called. Although for testing purposes this may not be a problem, the coupling reduces flexibility because the total method can only work with doubles/integers, as that's all the Math.abs() function can use. Although type coercion will allow the use of any primitive numeric type, these types have limitations. It's impossible to use another class such as BigInteger or a class for dealing with greater precision decimals or even alternative numbering systems such as Roman numerals.

The totalAbs function takes two doubles and converts them to their absolute values before adding them. This is inflexible because it only works with doubles. It's tied to doubles because that's what the Math.abs() static method requires. If, instead, using OOP an interface was created to handle any number that had this method:

 interface Numeric {
    public function 
abs(): Numeric;
}

It would then be possible to rewrite the totalAbs method to work with any kind of number:

 function totalAbs(Numeric valueNumeric value): Numeric {
    return 
value.abs() + value2.abs();
}

By removing the static method and using an instance method in its place the totalAbs method is now agnostic about the type of number it is dealing with. It could be called with any of the following (assuming they implement the Numeric interface)

 
totalAbs(new Integer(4), new Integer(-53));

totalAbs(new Double(34.4), new Integer(-2));

totalAbs(new BigInteger('123445454564765739878989343225778'), new Integer(2343));

totalAbs(new RomanNumeral('VII'), new RomanNumeral('CXV'));

Making the method reusable in a way that it wasn't when static methods were being used. By changing the static methods to instance methods, flexibility has been enhanced as the method can be used with any numeric type, not just numeric types that are supported by the Math.abs() method.

Broken encapsulation

Static methods also break encapsulation. Encapsulation is defined by Rogers[2] as:

the bundling of data with the methods that operate on that data

By passing the numeric value into the abs method, the data being operated on is being separated from the methods that operate on it, breaking encapsulation. Instead using num.abs() the data is encapsulated in the num instance and its type is not visible or relevant to the outside world. abs() will work on the data and work regardless of num's type, providing it implements the abs method.

This is a simple example, but applies to all static methods. Use of polymorphic instance methods that work on encapsulated data will always be more flexible than static method calls which can only ever deal with specific pre-defined types.

Further reading

Exceptions

The only exception to this rule is when a static method is used for object creation in place of the new keyword[3]. This is because the new keyword is already a static call. However, even here a non-static factory is often preferable for testing purposes[4][5].

References

  1. Popov, N. (2014) Don't be STUPID: GRASP SOLID! [online]. Available from: https://nikic.github.io/2011/12/27/Dont-be-STUPID-GRASP-SOLID.html
  2. Rogers, P. (2001) Encapsulation is not information hiding [online]. Available from: http://www.javaworld.com/article/2075271/core-java/encapsulation-is-not-information-hiding.html
  3. Sonmez, J. (2010) Static Methods Will Shock You [online]. Available from: http://simpleprogrammer.com/2010/01/29/static-methods-will-shock-you/
  4. Hevery, M. (2008) Static Methods are Death to Testability [online]. Available from: http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/
  5. Butler, T. (2013) Are Static Methods/Variables bad practice? [online]. Available from: https://r.je/static-methods-bad-practice.html
{ return function (callable $handler) use ($fn): callable { return function (RequestInterface $request, array $options) use ($handler, $fn) { return $handler($fn($request), $options); }; }; } /** * Middleware that applies a map function to the resolved promise's * response. * * @param callable $fn Function that accepts a ResponseInterface and * returns a ResponseInterface. */

Static methods

Summary of issues

  • Tight Coupling
  • Hidden dependencies
  • Global state (if also using static variables)

Tight Coupling

Use of static methods always reduces flexibility by introducing tight coupling[1]. A static method tightly couples the calling code to the specific class the method exists in.

 
function totalAbs(double valuedouble value2) {
    return 
abs(value) + abs(value2);
}

Here, the method totalAbs has a dependency on the Math class and the .abs() method will always be called. Although for testing purposes this may not be a problem, the coupling reduces flexibility because the total method can only work with doubles/integers, as that's all the Math.abs() function can use. Although type coercion will allow the use of any primitive numeric type, these types have limitations. It's impossible to use another class such as BigInteger or a class for dealing with greater precision decimals or even alternative numbering systems such as Roman numerals.

The totalAbs function takes two doubles and converts them to their absolute values before adding them. This is inflexible because it only works with doubles. It's tied to doubles because that's what the Math.abs() static method requires. If, instead, using OOP an interface was created to handle any number that had this method:

 interface Numeric {
    public function 
abs(): Numeric;
}

It would then be possible to rewrite the totalAbs method to work with any kind of number:

 function totalAbs(Numeric valueNumeric value): Numeric {
    return 
value.abs() + value2.abs();
}

By removing the static method and using an instance method in its place the totalAbs method is now agnostic about the type of number it is dealing with. It could be called with any of the following (assuming they implement the Numeric interface)

 
totalAbs(new Integer(4), new Integer(-53));

totalAbs(new Double(34.4), new Integer(-2));

totalAbs(new BigInteger('123445454564765739878989343225778'), new Integer(2343));

totalAbs(new RomanNumeral('VII'), new RomanNumeral('CXV'));

Making the method reusable in a way that it wasn't when static methods were being used. By changing the static methods to instance methods, flexibility has been enhanced as the method can be used with any numeric type, not just numeric types that are supported by the Math.abs() method.

Broken encapsulation

Static methods also break encapsulation. Encapsulation is defined by Rogers[2] as:

the bundling of data with the methods that operate on that data

By passing the numeric value into the abs method, the data being operated on is being separated from the methods that operate on it, breaking encapsulation. Instead using num.abs() the data is encapsulated in the num instance and its type is not visible or relevant to the outside world. abs() will work on the data and work regardless of num's type, providing it implements the abs method.

This is a simple example, but applies to all static methods. Use of polymorphic instance methods that work on encapsulated data will always be more flexible than static method calls which can only ever deal with specific pre-defined types.

Further reading

Exceptions

The only exception to this rule is when a static method is used for object creation in place of the new keyword[3]. This is because the new keyword is already a static call. However, even here a non-static factory is often preferable for testing purposes[4][5].

References

  1. Popov, N. (2014) Don't be STUPID: GRASP SOLID! [online]. Available from: https://nikic.github.io/2011/12/27/Dont-be-STUPID-GRASP-SOLID.html
  2. Rogers, P. (2001) Encapsulation is not information hiding [online]. Available from: http://www.javaworld.com/article/2075271/core-java/encapsulation-is-not-information-hiding.html
  3. Sonmez, J. (2010) Static Methods Will Shock You [online]. Available from: http://simpleprogrammer.com/2010/01/29/static-methods-will-shock-you/
  4. Hevery, M. (2008) Static Methods are Death to Testability [online]. Available from: http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/
  5. Butler, T. (2013) Are Static Methods/Variables bad practice? [online]. Available from: https://r.je/static-methods-bad-practice.html
{ return function (callable $handler) use ($fn): callable { return function (RequestInterface $request, array $options) use ($handler, $fn) { return $handler($request, $options)->then($fn); }; }; }}