The discussion about procedural programming versus object oriented programming, in the sense of which is "best", is mostly dominant in communities of programming languages that supports both programming paradigms. And the Internet is filled with blog posts, forum posts, YouTube tutorials, guides and documents about the procedural programming vs object oriented programming "issue".
The fact is that these discussions makes very little sense.
Programming is about solving problems and you can solve any programming problem in any programming language paradigm. In some programming languages you can even combine both paradigms. However, not all paradigms solve specific problems equally efficient. Therefore a discussion about one paradigm vs another doesn't make sense until you first define the problem you are trying to solve. Once you have defined your problem with some very clear parameters you can understand which paradigm is best suited to solve your problem.
Discussions that aren't centered around very specific problems are nothing more than theoretical babble and mudslinging.
In order to really understand a specific programming paradigm it is always a good idea to look at how it first evolved. What was the reason for its development? What problems existed with other programming paradigms that needed a new way of thinking? Was it a real world problem or simply an academic problem? And how has it since evolved?
So let's take a look at some history.
Before the advent of object oriented programming, around the end of the fifties, much software was developed using programming languages that emphasized unstructured programming, sometimes are referred to as first- and second-generation languages. Unstructured programming (or non-structured programming) is the historical earliest programming paradigm. It was heavily criticized for producing "spaghetti" code.
There are both high- and low-level programming languages that use non-structured programming. These include early versions of BASIC, COBOL, MUMPS, JOSS, FOCAL, TELCOMP, machine-level code, early assembler systems (those without procedural meta operators) and some scripting languages.
A program in a non-structured language usually consists of sequentially ordered commands, or statements, usually one in each line. The lines are usually numbered or may have labels which allows the flow of execution to jump to any line in the program (like with the unpopular GOTO statement).
Then in the sixties structured programming emerged - mainly due to the famous letter by Edsger W. Dijkstra Go To statements considered harmful.
Structured programming is a programming paradigm that improves the clarity, quality, and development of software by making use of subroutines, block structures and loops. This is contrast to using simple jumps such as the GOTO statement.
Later procedural programming was derived from structured programming. Procedural programming is based upon the concept of "procedure call". A "procedure call" is just another name for a "function call". Procedures are also known as functions, routines, subroutines or methods. A procedure simply contain a series of computational steps to be carried out. Any given procedure might be called at any point during a programs execution, including by other procedures or itself.
In the beginning all procedures were available to any part of a program as global data. In small programs this didn't present a problem, but as things got more complicated and the size of the program grew, small changes to one part of the program greatly effected many other parts. Nobody was planning for changes in the program and lots of dependencies existed. A minor change to one procedure would result in a cascade of errors in lots of other procedures that depended on the original code.
A new technique evolved which allowed data to be divided into separated scopes called "objects". Only specific procedures belonging to the same scope could access the same data. This is called data hiding or encapsulation.
In the beginning objects where not called objects, they where just viewed upon as separate scopes. Later when dependencies were reduced and connections between procedures and variables inside these scopes where viewed upon as isolated segments, the result gave birth to the concepts of "objects" and "object oriented programming".
Later, mainly due to the development of Java, certain "buzzwords" arose and "a procedure" or "a function" was no longer called a function, but was renamed "a method" when it resided inside a separate scope. Variables was also no longer called "variables", but was renamed "attributes" when they resided inside a separate scope.
Fact: An object is in essence simply a collection of functions and variables now referred too as "methods and attributes".
The way methods and attributes are kept isolated inside a separate scope is by the usage of what is called "a class". A class, once it is instantiated, is called an object.
Objects can reference each other and by such a reference the methods (functions) inside can "communicate" with each other. Objects can also "inherit" methods from other objects thereby extending such, this is called inheritance.
Inheritance is a way to reuse code and allow independent extensions of the software via public classes and interfaces. The relationships of objects give rise to a hierarchy. Inheritance was invented in 1967 for the programming language Simula 67.
Objects can also inherit methods from other objects and "override" these with added or changed functionality, this is called polymorphism.
How these different ideas are implemented vary greatly from programming language to programming language.
All in all object oriented programming is all about organization of code. It is an extension of procedural programming, and it is about avoiding a global scope and about sharing resources between classes and procedures. You extend functions by "borrowing" their blueprints without actually affecting the original code (inheritance). And you override functions without affecting the original code (polymorphism).
A funny thing to think about is that many object oriented programming languages are developed in a pure procedural programming language. PHP for example is developed in C and the object oriented features of PHP is a result of a pure procedural implementation. In other words, you are using a pure procedural programming language to develop an object oriented programming language.
Programming languages like Python, PHP, and C++ has build-in constructs that makes both procedural and object oriented programing possible.
Now, if you are feeling compelled to ask which programming paradigm to make use of simply take a look at the problem you're trying to solve and understand which paradigm is best suited at solving your specific problem. One paradigm is not automatically better than the other.