code: public static function XNPV($rate, $values, $dates)
      {
          $rate = Functions::flattenSingleValue($rate);
          if (!is_numeric($rate)) {
              return Functions::VALUE();
          }
          if ((!is_array($values)) || (!is_array($dates))) {
              return Functions::VALUE();
          }
          $values = Functions::flattenArray($values);
          $dates = Functions::flattenArray($dates);
          $valCount = count($values);
          if ($valCount != count($dates)) {
              return Functions::NAN();
          }
          if ((min($values) > 0) || (max($values) < 0)) {
              return Functions::VALUE();
          }
  
          $xnpv = 0.0;
          for ($i = 0; $i < $valCount; ++$i) {
              if (!is_numeric($values[$i])) {
                  return Functions::VALUE();
              }
              $xnpv += $values[$i] / pow(1 + $rate, DateTime::DATEDIF($dates[0], $dates[$i], 'd') / 365);
          }
  
          return (is_finite($xnpv)) ? $xnpv : Functions::VALUE();
      }
docs: XNPV.
  
  Returns the net present value for a schedule of cash flows that is not necessarily periodic.
  To calculate the net present value for a series of cash flows that is periodic, use the NPV function.
  
  Excel Function:
  =XNPV(rate,values,dates)
  
  @param float $rate the discount rate to apply to the cash flows
  @param array of float    $values     A series of cash flows that corresponds to a schedule of payments in dates.
  The first payment is optional and corresponds to a cost or payment that occurs at the beginning of the investment.
  If the first value is a cost or payment, it must be a negative value. All succeeding payments are discounted based on a 365-day year.
  The series of values must contain at least one positive value and one negative value.
  @param array of mixed    $dates      A schedule of payment dates that corresponds to the cash flow payments.
  The first payment date indicates the beginning of the schedule of payments.
  All other dates must be later than this date, but they may occur in any order.
  
  @return float