Many programmers like to talk about functional programming, but if you ask them if they have actually used it, most of the answers will be "no". The reason is simple: When we beginners in programming, we are taught to think in an imperative way, namely program flowcharts and steps. Therefore, this article will explain some important concepts of functional programming and how to write functional code in PHP.
Key Points
Important concepts of functional programming
Wikipedia defines functional programming as "a programming paradigm that treats calculations as evaluation of mathematical functions and avoids state and variable data". In functional programming, functions are regarded as first-class citizens, while in imperative programming, we focus mainly on data and the steps to change data to achieve the expected results. When we say that a function is a first-class citizen, this means that we can use functions like we use values in imperative programming. They can be passed as parameters to a function, defined within another function, or even returned as a result. In other words, "a function is a value". We'll discuss this again later, but functional programming has many other important concepts. To name just a few examples:
Invariance refers to the behavior that once the value of a variable is defined, it cannot be changed. Different languages have different implementations; for example, in PHP, the only way to keep a variable invariant is to define it as a constant.
Recursion is also prominent in functional programming. In imperative programming, when we need to manipulate sets or arrays, we can use loop structures such as for and foreach to iterate through each element and use temporary variables to save the current value. However, this approach is not possible in functional programming due to invariance. Recursion is the answer, because this bookkeeping is done implicitly through the call stack. Suppose we want to write a function to find the sum of all elements in an array (forget about the existence of array_sum() for now). In functional style, we will write:
<?php function sum($array) { if (empty($array)) return 0; else return $array[0] + sum(array_slice($array, 1)); } $total = sum(array(1, 2, 3)); // 6 ?>
Empty list will return 0, which is our basic condition. For an array containing multiple values, it returns the result of the addition of the first element to the recursive sum of all other elements.
If a function does not change the value of its own external object (such as global or static variables) and does not have any I/O effects (such as writing to files, databases, etc.), the function is said to have no side effects. Such functions are also called pure functions. For a given parameter set, the output of the pure function will always be the same, which results in another property called reference transparency. When a function is referenced transparent, we can replace the function with its value without affecting the behavior of the program. All mathematical functions are pure functions, while date functions, rand(), etc. are non-pure functions.
The above concepts can be implemented in almost any programming language, but first-class citizen functions and higher-order functions are the two most prominent features of functional programming. I've explained that a first-class citizen function means that a function can be treated as a value. A higher-order function is a function that can take a function as a parameter and can return a function as a result. Two important features recently added enable us to write higher-order functions in PHP: lambda expressions and closures.
The lambda function (also known as anonymous function) is just a function without a name. When we define an anonymous function, a reference to the function is returned, which is stored in a variable for later use. We use this variable to call the function when needed. Many different languages adopt this concept. In fact, you might use lambda functions in your daily JavaScript programming, using them as callbacks for different user interactions and Ajax calls.
$("#myButton").click(function () { // do something });
This code is very simple and easy to understand, which may make us forget about its functional aspect. PHP introduced this powerful feature in version 5.3, which allows us to write PHP code in a similar way:
<?php $square = function ($arg) { return $arg * $arg; }; $value = $square(2); // 4 ?>
When talking about functions, especially anonymous functions, it is important to understand how to deal with variable scope. For example, JavaScript allows you to access externally scoped variables inside lambdas, while PHP does not. lambda has its own scope inside, just like regular PHP functions.
Sometimes, you may want to refer to variables in the parent scope inside the function. Closures are similar to lambda functions, but slightly different, and you can access variables with external scopes. We can use "reach out" and bind external variables using PHP's use keyword, which was also introduced in PHP 5.3.
<?php function sum($array) { if (empty($array)) return 0; else return $array[0] + sum(array_slice($array, 1)); } $total = sum(array(1, 2, 3)); // 6 ?>
In this case, we do not pass interest rates every time the function is called. Instead, we define it externally and use the use keyword to make it available inside the function.
Simply put, some functions are functions created from existing functions, and their parameters are applied partially. You just need to pass the remaining parameters when calling the created function. We can use closures to create partial functions in PHP. This is an example to find the volume of a box based on its length, width, and height. All parameters are optional; if you do not provide all parameters, the function returns another function to accept the remaining necessary values.
$("#myButton").click(function () { // do something });
All parameters are optional. First check whether the caller has passed all parameters. In this case, we can directly return to the volume by multiplying the length, width, and height. If the number of parameters is less than the parameters, a new function is returned to find the volume of the given parameter preset. Now suppose we are looking for the volume of a box with a fixed length (e.g. 10). This can be done easily by taking 10 as the first parameter, or we can create a partial function by taking 10 as the first parameter and then request only the remaining values.
<?php $square = function ($arg) { return $arg * $arg; }; $value = $square(2); // 4 ?>
Currying is a special case of partial functions, where you convert a function that accepts multiple parameters into multiple functions that each accepts a single parameter. For example, similar to f(x,y,z) to f(x)(y)(z) (although PHP syntax does not allow nested function calls like this). If you are interested in learning more, Timothy Boronczyk has written an excellent article about currying with actual examples.
Pros and Disadvantages
The functions of functional programming have many practical uses in PHP. For example, the lambda function is widely used when using callback functions. For example, using the Slim framework, you can define the following route:
<?php function sum($array) { if (empty($array)) return 0; else return $array[0] + sum(array_slice($array, 1)); } $total = sum(array(1, 2, 3)); // 6 ?>
Slim calls the callback function when the requested URL matches this route. Vance Lucas has written some articles on other interesting use cases of Lambda functions before. Encourage secure programming by avoiding state and variable data. In functional programming, you should write functions that do only one thing and do no side effects each. This paradigm's emphasis on modularity and function simplicity can make it easier to infer your program based on different, small subroutines. Functional programming can also help you write code that focuses on what you want to achieve, rather than explicitly managing accidental events in the process (compare recursion to having to manage loop counter variables). But remember that some of the advantages traditionally related to functional programming do not apply to PHP because it is not designed as a functional programming language. For example, functions without side effects are ideal for parallel processing, but PHP scripts do not run this way. It is also not always easy to calculate the cost of recursive and lazy functions, and there may be serious performance problems due to internal overhead. Sometimes, it makes more sense to write programs with variability to improve efficiency. Perhaps the biggest drawback of functional programming is that it has a very steep learning curve for those who have been trained in imperatively. But overall, functional programming is fun, and learning it will provide you with new tools to think about old problems and help you grow as a programmer. It is not a universal solution, but can be applied to cleaner and more elegant PHP code as needed.
Summary
Functional programming is not just a programming paradigm; it is a way to think and reason about programs. If you can do functional thinking, you can program functionally in almost any language. In this article, we discuss the basics of functional programming, using the capabilities of PHP to write and provide examples of them. While the examples given in this article may not be practical for you, you will find many situations where functional styles can significantly improve the quality of the code you are writing. Try looking for cases like this, think functionally, and have fun! Pictures from Fotolia
Frequently Asked Questions about PHP Functional Programming
Functional programming and object-oriented programming are two different paradigms used in PHP. The main difference is how they manage state and data. In functional programming, functions are first-class citizens and have no concept of state. This means that given the same input, the function will always produce the same output. Object-oriented programming, on the other hand, revolves around objects and their interactions that maintain state and change over time. This can result in different outputs, even if the input is the same.
To start functional programming with PHP, you need to understand basic concepts such as pure functions, invariance, and higher order functions. Then you can start writing functions that do not change the state and have no side effects. PHP has built-in functions that support functional programming, such as array_map
, array_filter
, and array_reduce
. You can also use libraries like Laravel collections that provide smooth and convenient wrappers for using data arrays.
Functional programming in PHP allows you to write cleaner and easier to read code. It can help you avoid common programming problems such as side effects and state changes, which can make your code easier to predict and test. Functional programming also allows for more modular code because functions can be easily combined and reused.
While functional programming has its advantages, it also has some challenges. PHP was not originally designed for functional programming, so some features may not be as powerful or efficient as languages designed for functional programming. Additionally, functional programming requires different ways of thinking, and the learning curve can be steep for developers accustomed to imperative or object-oriented programming.
Yes, PHP is a multi-paragraph language, which means you can mix different programming styles. You can use object-oriented programming for the application parts that benefit from state and behavior, and functional programming for the application parts that benefit from stateless, side-effect-free functions. This gives you the flexibility to choose the best method for every part of the application.
The impact of functional programming on PHP performance may vary. In some cases, functional programming can write more efficient code because it avoids state changes and side effects. However, in other cases, it may be inefficient because it usually involves creating new objects rather than modifying existing objects. It is important to analyze and test your code to make sure it meets your performance requirements.
There are many resources available to learn PHP functional programming. Some good starting points include the PHP manual (which has a section on functional programming) as well as online tutorials and articles. There are also books on this topic, such as PHP Functional Programming by Gilles Crettenand.
Yes, you can use functional programming for web development in PHP. Functional programming can help you write cleaner and more modular code, which can be beneficial in a web development environment. However, remember that PHP is a multi-paragraph language, so you can use other programming styles, such as object-oriented programming, too.
In functional programming, error handling is usually done by using monads, a data structure that can represent calculations rather than values. In PHP, you can use the Maybe monad for error handling. This allows you to link operations together and if any operations fail, the rest of the chain will be skipped.
Functional programming can be used for large applications, but it depends on the specific requirements of the application. Functional programming can write cleaner, more modular code, which can be beneficial in large-scale environments. However, it can also be inefficient in some cases, so it is important to consider trade-offs.
The above is the detailed content of PHP Master | Functional Programming in PHP. For more information, please follow other related articles on the PHP Chinese website!