Weedpacket

  • 8 hours ago
  • Joined Aug 13, 2002
  • Weedpacket

    Huh. That function is doing two jobs. Should be two functions.

    function selections(int $t, int $n)
    {
    	if($n == 0) {
    		yield [];
    	} elseif($t == 0) {
    		yield array_fill(0, $n, false);
    	} elseif($t == $n) {
    		yield array_fill(0, $n, true);
    	} else {
    		foreach(selections($t - 1, $n - 1) as $s) {
    			yield [true, ...$s];
    		}
    		foreach(selections($t, $n - 1) as $s) {
    			yield [false, ...$s];
    		}
    	}
    }
    
    function subsets(int $needed, array $children)
    {
    	// Ensure the indices are normalised.
    	$children = array_values($children);
    	$select = fn($kept) => $children[$kept];
    	foreach(selections($needed, count($children)) as $selection) {
    		yield array_map($select, array_keys($selection, true));
    	}
    }
    
    
    $k = 3;
    $n = str_split('abcdefg');
    foreach(subsets($k, $n) as $subset)
    {
    	echo join($subset) . ' '; // 7!/(3!4!) = 35 different subsets.
    }

    Bonus for getting them in lexicographical order.

    Because the recursive part doesn't deal with the set elements directly, it can take some shortcuts and finish earlier.

    Note the anonymous function that has been pulled out of the array_map into $select. It's actually been pulled out of the loop to avoid instantiating a whole new Closure object on every iteration (that would be destroyed at the end of the iteration only for another new practically identical object to be created at the start of the next).

    • Is it the same bug that stops the thread listing from updating when replies are made? Because often people are replying but the only way to find that out is to actually look at the thread they replied in.

      We gave this new platform a pretty decent trial I think. Can we go back to vBulletin now, please?

    • No, it looks fine to me: , although the whole test can be simplified to just !empty($_SESSION['userid']).

      If you add linebreaks so that each occurrence of $_SESSION['userid'] is on a separate line, the line number in the log will be able to point to the occurrence it finds so offensive.

      • No, it looks fine to me: , although the whole test can be simplified to just !empty($_SESSION['userid']).

        If you add linebreaks so that each occurrence of $_SESSION['userid'] is on a separate line, the line number in the log will be able to point to the occurrence it finds so offensive.

        • Steve_R_Jones Yes; in the 8.4 announcement. The reply is there (now, after I looked at it again), but the front page isn't updated.

          • Testing ... testing ... does this get through?

            Well, that's a relief. I tried posting earlier but just got the "Oops something went wrong" message.

          • And this is happening again. Now it's on the 8.4 release announcement post. I added a reply and got the "Something went wrong" toaster when submitting but (a) the post did get posted, but (b) the thread listing didn't update (it still says the most recent reply was @dalecosp's a day ago).

            I'm wondering how much activity is going unnoticed and if there are people out there feeling themselves ghosted.

            And guess what happened when I tried to post this reply 🤣

            • And this is happening again. Now it's on the 8.4 release announcement post. I added a reply and got the "Something went wrong" toaster when submitting but (a) the post did get posted, but (b) the thread listing didn't update (it still says the most recent reply was @dalecosp's a day ago).

              I'm wondering how much activity is going unnoticed and if there are people out there feeling themselves ghosted.

              • A tweak tosprintf.
                Just fiddling around and stumbled on this change.

                Consider the statement $m =sprintf("Message (%s): %s\n", date('Y-m-d h:i:s'), $message_slug);. This could have been written more performantly as $m = "Message (" . date('Y-m-d h:i:s') . "): $message_slug\n";, but that's harder to read and more fraught if the format changes.

                In PHP 8.3, the bytecode for that sprintf call would look something like:

                INIT_FCALL 3 128 string("sprintf")
                SEND_VAL string("Message (%s): %s\n") 1
                INIT_FCALL 1 96 string("date")
                SEND_VAL string("Y-m-d h:i:s") 1
                V1 = DO_ICALL
                SEND_VAR V1 2
                SEND_VAR CV0($message_slug) 3
                V2 = DO_ICALL

                In 8.4, it becomes

                INIT_FCALL 1 96 string("date")
                SEND_VAL string("Y-m-d h:i:s") 1
                V1 = DO_ICALL
                T3 = ROPE_INIT 5 string("Message (")
                T3 = ROPE_ADD 1 T3 V1
                T3 = ROPE_ADD 2 T3 string("): ")
                T3 = ROPE_ADD 3 T3 CV0($message_slug)
                T2 = ROPE_END 4 T3 string("\n")

                Yes, that's exactly what it looks like: what you'd have if you'd written $temp = date('Y-m-d h:i:s'); $m ="Message ($temp): $message_slug\n";

                Basically, what happens is that a v?[sf]?printf() call in which the format pattern contains only plain %s (and %d) specifiers is converted into concatenations before being compiled to bytecode. PHP is very efficient at concatenating strings, and this also saves the costs of a function call and parsing the format string. Win-win-win.

                There are limitations. As soon as any format specifier gets fancier (like %14s) then it's back to a sprintf call. Also, the format string has to be provided literally, so it won't work if said format came from, say, an i18n multilingual collection (in that particular situation you're probably better served by the Intl extension's MessageFormatter class).

                • Actually, it's 8.4.1; between tagging 8.4 and the announcement, security fixes were applied which meant bumping the version number.

                  The highlights are here:
                  https://www.php.net/releases/8.4/en.php

                  The highlights of the highlights:

                  • Property hooks. Previous PHP had (and it still has) magic __get and __set methods for getting your object to pretend to have properties it doesn't actually have. These were awkward for several reasons, not the least of which being that such properties were invisible to IDEs and static analysis (since they didn't actually exist). With property hooks you can declare an ordinary object property, while attaching your own getter/setter code to them to be invoked when they're accessed. You can also write getter/setter code that has the same effect without having to declare an actual property. The magic methods are still there, suitable for situations where you want your object to be able to respond to arbitrary property names being thrown at it, but if you know what those names are in advance (like, your __get is just a big switch listing them), then property hooks may well be the way to go.

                  • Asymmetric Visibility. Now you can make a property that is public for reading, but writeable only privately. Previously, if you wanted that sort of control you had to make the property private and write getters and setters with the visibility you wanted.

                  • #[\Deprecated] Attribute
                    You know how PHP deprecates things well in advance of their removal, to give you notice and time to upgrade: when a deprecated feature is used a message is logged notifying you. Now PHP library and application authors can use that mechanism in their own products.

                  • New ext-dom features and HTML5 support. Because PHP's HTML parsing and DOM manipulation facilities really needed it. The new DOM (the old one remains for legacy support) has its own namespace.

                  • Object API for BCMath. Up until now, big-number arithmetic using the BCMath extension involved passing strings of digits back and forth between various bc*() functions. Now the bignums have their own class (\BcMath\Number) and can be used with arithmetic and comparison operators directly (e.g. for Numbers $num1 and $num2 you can write $result = $num1 + $num2; to get their sum, and $result will also be a Number). They also implement __toString, so you can get that string of digits back at the end when you expect to. (Oh, and did I mention it's now quite a bit faster, precisely because it's not constantly converting back and forth between those strings of digits?)

                  • New array_*() functions. I use array functions probably way too much. Without looking at the new array_find() function, how would you find an element of an array that returns true for some test?

                  • PDO driver specific subclasses. For a long time, even PDO assumed everyone was using MySQL: it had to in order to accommodate MySQL/MariaDB's syntax quirks. This was especially problematic when it came to how identifiers and strings were quoted in SQL. It also meant that when you created a PDO connection object, it came with a whole bunch of methods that had nothing to do with the database you were connecting to. Now, each DBMS has its own subclass of PDO.

                  • new MyClass()->method() without parentheses. Instead of (new MyClass())->method().

                  And a bunch more things. Lazy objects, a new JIT compiler, round() gets additional rounding modes (and an Enum that lists the modes), the ICU library has been bumped to version 75 and PCRE to 10.44...

                  Being a minor release, there are some BC breaks and deprecations: if a typed function parameter can be nullable then you're warned if you don't explicitly say so in the type declaration, a few extensions that have basically been dead for however long have been packed off to PECL, E_STRICT is a deprecated error reporting level, some mysqli features have been deprecated, ...

                  The release announcement is linked above. The migration guide is where you expect it:
                  https://www.php.net/manual/en/migration84.php

                • While searching for something else I stumbled on this old post from 2010:
                  Weedpacket
                  wherein I presented the curry function

                  function curry($f)
                  {
                          if(!is_callable($f))
                          {
                                  trigger_error(E_USER_WARNING, "curry()'s argument needs to be callable.");
                                  return null;
                          }
                          return function($x)use($f)
                          {
                                  // An arbitrary number of arguments could be passed...
                                  return function()use($x,$f)
                                  {
                                          $args = func_get_args();
                                          // ...and the first one already HAS been...
                                          array_unshift($args, $x);
                                          return call_user_func_array($f, $args);
                                  };
                          };
                  }
                  

                  It's been a long while since I've had to make use of call_user_func_array, so I wondered what that function would look like if I wrote it today. So I wrote it today:

                  function curry(callable $f): callable
                  {
                  	return fn($x) => fn(...$args) => $f($x, ...$args);
                  }
                  

                  Just a little snapshot of 14 years' worth of PHP language evolution.

                  • And again here. And this text box is still telling me that it hasn't had any replies in over a month. What am I, chopped liver?

                  • Off the top of my head, there isn't some transaction thing going on is there? So that while you're looking from the terminal the transaction that added the shipping line-item hasn't yet been committed so wouldn't be visible from another session?

                    • Is there anything in your server's error logs? Have you checked with the browser to see if it is actually receiving a 500 response?
                      What happens in PHP 8.1? There may be something relevant here or here.

                      Are you really intending $_POST['content_txt'] to only contain integers?

                      Is there any significance in that you have two branches that check recordToDelete, with one checking if $_POST['recordToDelete'] is set and the other checking $_GET['approve']?

                      Is there some reason you use mysqli_query($con, $query) instead of $mysqli->query() at a few points? Is there some reason you have two db connections?

                      Also, you really need to learn to use prepared statements.

                      In passing, if you're not going to be using the value of a column returned by a SELECT statement you don't need to include it in the columns returned. "SELECT filename FROM steam_downloads WHERE idlesson=?" will work just fine.

                      (Oh, and one more aside, one of your spans has a style of "margin-bottem"...)

                      • TIL:

                        
                        function cmp($n, $m) { return $n - $m;}
                        
                        $el_gordo = 3*(PHP_INT_MAX >> 2);
                        
                        $data = [0, 1, 6, -42, 25, -1000, $el_gordo, -$el_gordo];
                        
                        usort($data, cmp(...));
                        
                        echo join(' ', $data);

                        When passed $el_gordo and -$el_gordo, cmp returns a double (equivalent to (3/2)PHP_INT_MAX) instead of an integer. and usort doesn't like that. It won't complain, but it doesn't like that.

                      • sneakyimp YUCK. I do not like this idea very much. Seems like it opens the door to security problems.

                        It's nothing new; this has always been the case with PHP. So if there is a security hazard (which requires bad actors having write access to source code) it's one that has always been there. It's no different from

                        <?php
                        $fo=42;
                        $fο=17;
                        echo $fo;

                        except a little more fragile (because nonbreaking spaces don't copy-paste quite so reliably as omicrοn) and harder to spot if syntax highlighting doesn't assume all identifiers are in ASCII.

                      • Yeah, the "last replied" didn't update either.

                        On subject:
                        Did You Know:
                        PHP's "__construct" is just a well-known name for an ordinary instance method? The only special treatment it gets is the property promotion syntax and an exemption from type variance constraints.

                        class Foo
                        {
                        	public function __construct(public int $prop)
                        	{
                        		return 'Hello, World!';
                        	}
                        }
                        
                        $k = new Foo(42);
                        echo $k->prop, "\n";
                        echo $k->__construct(17), "\n";
                        echo $k->prop, "\n";
                        • sneakyimp

                          TIL (not really today, but it came up again today) that a nonbreaking space is a valid character that can be used in identifiers.

                          <?php
                          $fo = 42;
                          $fo = 17;
                          echo $fo ;

                          Outputs 42 because of course that's $fo  in the first and third positions, but only $fo in the middle.

                          And it's also valid in constants as well (strictly speaking, almost all strings are valid as constant names, but most of them can't be used without wrapping them in constant()):

                          <?php
                          define(' ', 42);
                          function foo() { return ;}
                          echo foo();

                          Edit: Hey; still got the error message but the thread got bumped to the top of the list!