Jump to content

Is it possible to pass multiple variables through one method argument?


chesse18
Go to solution Solved by kicken,

Recommended Posts

Hey guys, new here. (I got blocked on Stack Overflow because of downvote trolls ruining my rep after building it up).

So, I'm curious if you can pass multiple variables through a method or function, without using an array.

For example, a function that calls another function; for example, the reason I'm trying to use this is to make a Database() class, so I can cleanly, easily, and more elegantly talk to my database. In the ...bind_param() function, it takes these arguments in order: ...bind_param($stmt, $typeDefString, ...list of variables here...); For example, take a look at the code I have written below (irrelevant pieces of code are not included to save space):

 

<?php

class Database {
  // Properties
  public $conn;
  public $query = "";
  public $typeString = "s";
  public $selVarArray;
  private $selResult;
  
  // Methods
  function startConnection($conn) {
    $this->conn = $conn;
  }
  
  function prepareSelect($query, $typeString, $selVars) {
    $this->query = $query;
    $this->typeString = $typeString;
    $this->selVars = $selVars;
  }
  
  function selectFromDb() {
    //... Some code for setting up mysqli statement
    if ($this->selVars !== null) {
      mysqli_stmt_bind_param($stmt, $this->typeString, $this->selVars);
    }
    //.. Some code to execute query and fetch mysqli result, then this:
    $this->selResult = $result; // Sets $selResult property for later use
  }
  
  function fetchMultiple($functionToRun) {
    if ($this->selResult->num_rows > 0) {
      while ($row = $this->selResult->fetch_assoc()) {
        $functionToRun($row);
      }
    }
  }

  function fetchSingle($functionToRun) {
    if ($this->selResult->num_rows > 0) {
      $row = $this->selResult->fetch_assoc();
      $functionToRun($row);
    }
  }
  
} // End of class





 

The above code is the (relevant parts of) my Database() class. Below, is my test case page, and how I go about using this class to select database items:

 

<?php
// This is just a test case, in this example it would be to grab and display the user's email address and phone number.

$id = 14;
$name = "Mary";
$sel = new Database();
$sel->startConnection($conn); // Initializes connection to database
$sel->prepareSelect("SELECT userEmail, userPhone FROM users WHERE userID=? OR userName=?;", "is" /* <-- typeDefString*/, [$id, $name]);
$sel->selectFromDb(); // <-- Doesn't require any arguments
$sel->fetchMultiple(function($row) {
  // Code to control/display data to page here
  echo 'Your email: '.$row["userEmail"].' Your Phone Number: '.$row["userPhone"];
});

 

Now, allow me to clarify my question now that I have an example and relevant use case for it.

In the prepareSelect() method, I need to pass through (in order): $query, $typDefString, $listOfVars

NOW, this code works perfectly fine, if you pass through only one variable (or none, in cases of not needing to use ...bind_params() in which I can set $listOfVars null). The issue is, if you need to pass through multiple variables, which the global ...bind_params() function is able to take any number of variables there and they later get translated into where the ? marks are in the query, if you know how prepared statements work, you know what I'm talking about.

HOWEVER, passing through an array into prepareSelect() (which then gets passed into ...bind_params() ), is not valid. The only argument definition that can be passed through ...bind_params() in that spot are variables, otherwise I'd simply use implode() with string values, but that kind of defeats the point/purpose of the security of prepared statements, even if it let you use string values there.

Also, they have to be in list form, like this: ...bind_params($stmt, $typeDefString, /* List of vars, can be any number of them --> */ $varOne, $varTwo, $varThree, $varFour, $etc);

So, I guess what I'm asking is... is it possible, and if it is possible, how can I allow the 3rd argument in my prepareSelect() method, pass through a varying number of variables, into ...bind_params(), in list form?

I hope I have been clear enough to have this question makes sense. If you need any other info, please feel free to ask. If you have a solution or method, please let me know! 

Link to comment
Share on other sites

3 minutes ago, kicken said:

You want Variable length arguments which are accomplished using the ... operator.

    // Using ... collects arguments and puts them into an array
    public function prepareSelect($query, $ts, ...$params){
        // Using ... here breaks $params into individual arguments.
        $this->bind_param($ts, ...$params);
    }

 

Wow, that's actually extremely helpful. I feel very stupid for not realizing that was an obvious solution. This will also definitely help when creating a method for inserting data into the database. I'm all about trying to have neat and clean code, and I'm also a firm believer of class/method programming rather than functional programming... at least in PHP. You end up with too much of the exact same code written everywhere... I've found with PHP especially it's best to have the least amount of code do the most amount of work. Typically of all programming however IMO it's extremely important in PHP in general.

Link to comment
Share on other sites

or you could use the much simpler, more consistent, and more modern PDO extension, which doesn't have any function/method that takes variable length arguments. in fact, you don't need to use explicit binding with the PDO extension. you can simply supply an array of inputs to the ->execute([...]) method call, which can be an empty array if you happen to dynamically build a query that doesn't have any input parameters in it.

Link to comment
Share on other sites

48 minutes ago, mac_gyver said:

or you could use the much simpler, more consistent, and more modern PDO extension, which doesn't have any function/method that takes variable length arguments. in fact, you don't need to use explicit binding with the PDO extension. you can simply supply an array of inputs to the ->execute([...]) method call, which can be an empty array if you happen to dynamically build a query that doesn't have any input parameters in it.

Is PDO even that safe compared to mysqli prepared statements? Or in reality, is there really any difference security wise? Because, I've seen some PDO code, and while yes the above code is much more complex... for simple sql queries, every PDO script I've seen that does the same exact thing as something I'd write with prepared statements looks way messier, at least visually/readability wise. I've also looked around and seen that while PDO is preferred, there really isn't any security benefits from it over PROPER mysqli prepared statements. 

So, what other benefits would you really gain from using PDO over mysqli PS? Besides the simpler WAY to write it, at least to me it doesn't seem cleaner, despite being simpler, yes, but I could definitely be wrong. Interested in your input on this.

Link to comment
Share on other sites

true prepared queries, regardless of the database extension, are equally safe, since they separate the parsing of the sql query syntax from the evaluation of the data. PDO has emulated prepared queries, that should be avoided whenever possible, since, if you haven't set the character set that php is using to match your database tables, which is rarely shown in connection code examples, it is possible for sql special characters in a value to break the sql query syntax, which is how sql injection is accomplished.

the PDO examples you have seen that look messier, are probably using named place-holders. PDO also has positional ? place-holders, just like the mysqli extension, which makes converting from using the mysqli extension to PDO straight forward, since the sql query syntax using ? place-holders is exactly the same. to convert to using the PDO extension, you would eliminate the existing msyqli bind_param() call, and supply the array of input data to the ->execute() call. because you can directly fetch data from a PDO prepared query, exactly the same as for a non-prepared query, you don't need to deal with mysqli's bind_result() or get_result() (which is not portable between systems that use and don't use the msyqlnd driver.)

another issue with the mysqli extension is that the procedural and OOP notation have different php error responses (though php finally made the mysqli connection always throw an exception upon an error.) things which are fatal problems, that produce fatal php errors when using OOP notation, only produce warnings when using mysqli procedural notation, and allow code to continue to run, producing follow-on errors.

an advantage of learning the PDO extension, is that the same php statements work with 12 different database types, so, if you ever need to use a different database type, you don't need to learn a completely new set of php statements for each one.

 

 

Edited by mac_gyver
  • Like 1
Link to comment
Share on other sites

Another problem with mysqli is that it was obviously written by 2 teams of developers who never spoke to one other.

  • Executing a query produces a result object.
  • Executing a prepared statement produces a statement object.
  • The methods these classes to use to process the outputs are completely different.

With PDO, the class methods used are the same for both, making life much easier,

  • Like 1
Link to comment
Share on other sites

11 hours ago, mac_gyver said:

true prepared queries, regardless of the database extension, are equally safe, since they separate the parsing of the sql query syntax from the evaluation of the data. PDO has emulated prepared queries, that should be avoided whenever possible, since, if you haven't set the character set that php is using to match your database tables, which is rarely shown in connection code examples, it is possible for sql special characters in a value to break the sql query syntax, which is how sql injection is accomplished.

the PDO examples you have seen that look messier, are probably using named place-holders. PDO also has positional ? place-holders, just like the mysqli extension, which makes converting from using the mysqli extension to PDO straight forward, since the sql query syntax using ? place-holders is exactly the same. to convert to using the PDO extension, you would eliminate the existing msyqli bind_param() call, and supply the array of input data to the ->execute() call. because you can directly fetch data from a PDO prepared query, exactly the same as for a non-prepared query, you don't need to deal with mysqli's bind_result() or get_result() (which is not portable between systems that use and don't use the msyqlnd driver.)

another issue with the mysqli extension is that the procedural and OOP notation have different php error responses (though php finally made the mysqli connection always throw an exception upon an error.) things which are fatal problems, that produce fatal php errors when using OOP notation, only produce warnings when using mysqli procedural notation, and allow code to continue to run, producing follow-on errors.

an advantage of learning the PDO extension, is that the same php statements work with 12 different database types, so, if you ever need to use a different database type, you don't need to learn a completely new set of php statements for each one.

 

 

 

9 hours ago, Barand said:

Another problem with mysqli is that it was obviously written by 2 teams of developers who never spoke to one other.

  • Executing a query produces a result object.
  • Executing a prepared statement produces a statement object.
  • The methods these classes to use to process the outputs are completely different.

With PDO, the class methods used are the same for both, making life much easier,

Thank you. I've honestly solely used mysqli forever since I've been doing backend (few years), but I think you've convinced me to start using PDO > mysqli. Until now I just didn't realize there was actually any benefit from it, and had just assumed it was simply another method of doing it, rather than something actually better than.

Would either of you happen to have a good resource/link or documentation for proper use of PDO/prepared statements and the use of proper PDO queries, so I don't get misconstrued? Based on your reply, it seems that the majority of "tutorials" or guides and other resources don't cover essential bits and pieces of information that could possibly lead to insecure or downright wrong methods of using PDO. If I'm going to start using PDO I want to do it properly and not like some newbie beginner.

Link to comment
Share on other sites

15 hours ago, chesse18 said:

Hey guys, new here. (I got blocked on Stack Overflow because of downvote trolls ruining my rep after building it up).

I have never heard of this.  Are there some questions you can link that illustrate what happened to you?  I have a decent amount of rep from answering questions at SO, but I have noticed that the php zealots have taken over with their mission of closing any question that remotely resembles one that might have been asked in the past, so it's very hard for inexperienced people to have a question that isn't closed in short order.  It's ironic that they say they want new users, but the mods involved in looking at php questions seem to think that there only mission is to compress everything down to previously asked questions at this point.

Candidly, I don't see any advantage to your class over mysqli or PDO by itself.  Since the class is useless without a database connection, that tells you you should at very least have a constructor that requires a db connection, rather than a separate startConnection method with a parameter that doesn't actually start a connection -- just dependency injects a connection resource which you depend upon in order for any of the code you have to work.

Looking at the semantics, you wrote a couple of select query helper functions, that only work with the simplest queries possible.    

A decent wrapper around PDO that actually does offer some value for people is Doctrine DBAL.  

Doctrine is an Object Relational Mapping(ORM) component, used by the Symfony project to provide sophisticated relational database to php object mapping.  It's an implementation of the Data Mapper pattern

In general, you tend to see that sophisticated OOP code is implementing OOP Design patterns that have been named.  The link I provided gives you an idea of what the pattern tries to accomplish and some simple examples of how a particular pattern could be implemented.  There's another ORM pattern you might have heard of called "Active Record" and has a number of framework ORM's which have implemented the "Active Record" pattern.  CakePHP is a long standing one, and Ruby on Rails was a famous implementation of it.

The Doctrine ORM depends on the "Database Abstraction Layer (DbAL) library, but DBAL can be used by itself and provides the same sort of things you are trying to provide.

One thing to see is that the ORM's from the major frameworks across the board, have a query class which allows you to programmatically build up sql queries.  This is really the heart of what you have focused on, only in a very limited and unsophisticated way.  In comparison take a look at the documentation for the DbAL query builder class.

Not trying to be a downer here, but there are a huge number of database classes available, with documentation and unit tests out there you can start using with little more than a "composer require name-of-package", rather than reinventing a restrictive wheel, that depends on the spread operator.

Link to comment
Share on other sites

I personally like Active Record Pattern and I implement on my websites that I develop and design as it makes the job easier. The website goes up faster and lot less coding when all you have to do is transport the classes over and make a few minor modifications to the code. I didn't use a library and learn how to do ARP by watching a tutorial which is kind of ironic as the person who did the tutorial was using mysqli, but I like using PDO so I just switched it over to that. Active Record is good for small to medium size websites in my opinion and if I was building a large website I probably go with MVC or something like that.  The reason I don't use libraries is I like to code and see how it basically it is done at the native level when it comes to PHP and I don't use libraries like jQuery with JavaScript as I use plain Vanilla js. I see comments all the time that a person writes more code with Vanilla JavaScript, but I personally don't think it is all that much more code being written (other than the helper functions). Sorry getting off topic a little bit.

Link to comment
Share on other sites

2 hours ago, gizmola said:

I have never heard of this.  Are there some questions you can link that illustrate what happened to you?  I have a decent amount of rep from answering questions at SO, but I have noticed that the php zealots have taken over with their mission of closing any question that remotely resembles one that might have been asked in the past, so it's very hard for inexperienced people to have a question that isn't closed in short order.  It's ironic that they say they want new users, but the mods involved in looking at php questions seem to think that there only mission is to compress everything down to previously asked questions at this point.

Candidly, I don't see any advantage to your class over mysqli or PDO by itself.  Since the class is useless without a database connection, that tells you you should at very least have a constructor that requires a db connection, rather than a separate startConnection method with a parameter that doesn't actually start a connection -- just dependency injects a connection resource which you depend upon in order for any of the code you have to work.

Looking at the semantics, you wrote a couple of select query helper functions, that only work with the simplest queries possible.    

A decent wrapper around PDO that actually does offer some value for people is Doctrine DBAL.  

Doctrine is an Object Relational Mapping(ORM) component, used by the Symfony project to provide sophisticated relational database to php object mapping.  It's an implementation of the Data Mapper pattern

In general, you tend to see that sophisticated OOP code is implementing OOP Design patterns that have been named.  The link I provided gives you an idea of what the pattern tries to accomplish and some simple examples of how a particular pattern could be implemented.  There's another ORM pattern you might have heard of called "Active Record" and has a number of framework ORM's which have implemented the "Active Record" pattern.  CakePHP is a long standing one, and Ruby on Rails was a famous implementation of it.

The Doctrine ORM depends on the "Database Abstraction Layer (DbAL) library, but DBAL can be used by itself and provides the same sort of things you are trying to provide.

One thing to see is that the ORM's from the major frameworks across the board, have a query class which allows you to programmatically build up sql queries.  This is really the heart of what you have focused on, only in a very limited and unsophisticated way.  In comparison take a look at the documentation for the DbAL query builder class.

Not trying to be a downer here, but there are a huge number of database classes available, with documentation and unit tests out there you can start using with little more than a "composer require name-of-package", rather than reinventing a restrictive wheel, that depends on the spread operator.

As for the first part of this, it was mostly just me getting butthurt, TBH--a couple years ago, when I was completely new to PHP, and also SO--I had asked a couple of questions that, in hindsight, were pretty stupid. They were clear and concise, which wasn't the issue, but they were just stupid, simple things that probably didn't need asking (like how to hash a file name when working with directories, yes, I had a use case for it). However, a couple of years later, after not really asking any questions and having minimal usage/activity on SO, I come back to find that I was blocked from asking questions. I found it useless to go back and edit them to be better questions, and wait and PRAY for someone to find such old questions in order to gain back the posting permission, so I simply deleted them, in hopes that maybe it would clear the block after a bit. Turns out, I was dead wrong, as after deleting 2 of them, the site figured out what I was doing while mass deleting old questions of mine, and gave me a prompt, "You sure you want to delete this question? Deleting this question will not give you back posting privileges" or something along those lines. I deleted them anyway and moved on.

Also, the class I'm using does have a constructor for the connection, I honestly don't know why I changed it for the code example but it's there and works. Also, as for the "simplest queries possible", yes, that's perfectly fine. The app I'm building doesn't have a lot of functionality, and really only needs simple INSERT, UPDATE, or SELECT queries. Anything more than that, and this code would be much different. I also want to mention that regardless of PDO or mysqli, for me, using a class, albeit a very basic one, is perfectly fine for this use-case; it's better than simply re-writing thicker code blocks, plus, while it could just as easily be done with a simply function, I get more control over it, regardless.

Also, as for the rest, yes they're useful in most cases, but I really don't "need" them. This project isn't a massive business website where I've got complicated queries or functionality. Literally the most complicated part of this site is form handling on inventory, which in itself is not difficult at all. I personally see zero benefit from running composer or anything else like I would on a larger scale project, you wouldn't use React to develop a static 5 page website now would you? Same concept here. My goal here is simply to compress my already current code base, which I have managed to do now, managing to get my entire function library compressed into 6 classes

However I do appreciate the advice. Just seems very unnecessary. However PDO on the other hand I will be delving into and switching my code base over to that from now on because I do however see the benefit of that.

Link to comment
Share on other sites

45 minutes ago, Strider64 said:

I personally like Active Record Pattern and I implement on my websites that I develop and design as it makes the job easier. The website goes up faster and lot less coding when all you have to do is transport the classes over and make a few minor modifications to the code. I didn't use a library and learn how to do ARP by watching a tutorial which is kind of ironic as the person who did the tutorial was using mysqli, but I like using PDO so I just switched it over to that. Active Record is good for small to medium size websites in my opinion and if I was building a large website I probably go with MVC or something like that.  The reason I don't use libraries is I like to code and see how it basically it is done at the native level when it comes to PHP and I don't use libraries like jQuery with JavaScript as I use plain Vanilla js. I see comments all the time that a person writes more code with Vanilla JavaScript, but I personally don't think it is all that much more code being written (other than the helper functions). Sorry getting off topic a little bit.

I can get on board with that. Despite many telling you that you shouldn't use jQuery anymore, I still use it, as it does have its usefulness. And actually, if you know how to use jQuery properly, you WILL write 30-40% less code, that does the exact same thing. I don't use it heavily, however I do use it. For larger projects I use Node.js anyway, so for simple projects like this one, IMO it's best not to overcomplicate it. Just sweet old HTML/CSS, PHP, JavaScript/jQuery. Also, I use VSCode for an IDE, and there's an extension for SCSS/SASS that will watch for SCSS/SASS updates, and automatically transpile it for you into CSS, which is MUCH quicker than manually running a compile command. SCSS is something I'll probably be using on every project I take on until there's a better alternative, so far SCSS has been a life saver and made CSS much more enjoyable.

Anyway, also getting off topic, but yes, I also prefer native or at least close to native-level language usage on simple apps/sites. Like I stated above, if this were a JS question, what would be the point in using React to build a static 5 page website that probably won't get updated for years besides maybe a few images? Lots of very small businesses have web apps like this. I mean, yeah... it'd probably be quicker to write up said app in React, but it would be pointless, when simple native HTML/CSS/JS works and IMO is much easier to read unless you're doing a massive project.

Link to comment
Share on other sites

On 2/16/2023 at 5:26 PM, chesse18 said:

Also, as for the rest, yes they're useful in most cases, but I really don't "need" them. This project isn't a massive business website where I've got complicated queries or functionality. Literally the most complicated part of this site is form handling on inventory, which in itself is not difficult at all. I personally see zero benefit from running composer or anything else like I would on a larger scale project, you wouldn't use React to develop a static 5 page website now would you? Same concept here. My goal here is simply to compress my already current code base, which I have managed to do now, managing to get my entire function library compressed into 6 classes

However I do appreciate the advice. Just seems very unnecessary. However PDO on the other hand I will be delving into and switching my code base over to that from now on because I do however see the benefit of that.

The analogy of comparing composer to react isn't correct in my opinion.  More like composer = npm. 

Every project should have a composer.json file in my opinion.  Takes 2 seconds to make, and will provide you config for an autoloader and a correct way to namespace and place your classes, even if you don't use any others.   Run composer init, answer a few questions and you are off and running.

Also points you gently in the direction of putting your "public" (web accessible) files under public and not having pointing your webroot with a tree of all your files, which at best is a mess and worse a potential security issue.  You include the generated PSR-1 or PSR-4 autoloader in a bootstrap or ideally a front controller.  Could be as simple as something like this:

if (!defined('ABSPATH')) {
    define('ABSPATH', dirname(__FILE__) . '/');
}

require_once(ABSPATH . "../vendor/autoload.php");

At some point with any web app, you might want logging, or a mailer, or file handling, routing or a simple HTTP request/Response class.  With 5 minutes you literally are up and running with unit tested code in most cases.  The Symfony components alone have an extensive list of well designed time saving classes.  

Link to comment
Share on other sites

On 2/16/2023 at 5:35 PM, chesse18 said:

 for simple projects like this one, IMO it's best not to overcomplicate it. Just sweet old HTML/CSS, PHP, JavaScript/jQuery. Also, I use VSCode for an IDE, and there's an extension for SCSS/SASS that will watch for SCSS/SASS updates, and automatically transpile it for you into CSS, which is MUCH quicker than manually running a compile command. SCSS is something I'll probably be using on every project I take on until there's a better alternative, so far SCSS has been a life saver and made CSS much more enjoyable.

SCSS is some good stuff, and the built in compiler is a great time saver compared to setting up webpack.

Active Record: not a fan of it honestly.  Seems nice at first, but the more you use it, the more limiting and kinda dumb it is.  Data mapper pattern is far superior in many ways, I won't go into, but to each their own.   Worked on a project not too long ago (consumer service) where they used Laravel, and then Dev's spent a bunch of time adding things to Eloquent to add a home grown version of doctrine repositories.    

Link to comment
Share on other sites

I agree setting up webpack is a slog, but IMO using laravel-mix makes it much easier; and then everything just runs in the background. Despite the name it's not actually tied to Laravel (and I agree with gizmola about Active Record and Laravel's implementation - it's not always awesome) but it kind of does walk you through some of the configuration you typically have to do manually in webpack. It also handles prefixing, minifying, uglifying, and transpiling pretty much out of the box for as much as that may be necessary to your site.

Link to comment
Share on other sites

On 2/20/2023 at 8:48 PM, maxxd said:

I agree setting up webpack is a slog, but IMO using laravel-mix makes it much easier; and then everything just runs in the background. Despite the name it's not actually tied to Laravel (and I agree with gizmola about Active Record and Laravel's implementation - it's not always awesome) but it kind of does walk you through some of the configuration you typically have to do manually in webpack. It also handles prefixing, minifying, uglifying, and transpiling pretty much out of the box for as much as that may be necessary to your site.

Since I'm more of a symfony guy, symfony has something very similar:  webpack encore.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.