Generally speaking, looping is bad in SQL. For what you described, I can't imagine why it would warrant a loop. However, here is a set based method with simple joins that would eliminate everything but a single procedure.
declare @tbl_products table (
                            id int, 
                            title varchar(16))
insert into @tbl_products
values
(1,'prod1'),
(2,'prod2'),
(3,'prod3'),
(4,'prod4'),
(5,'prod5')
declare @tbl_attributes table (
                                id int,
                                title varchar(16))
insert into @tbl_attributes
values
(1,'attr1'),
(2,'attr2'),
(3,'attr3'),
(4,'attr4'),
(5,'attr5')
declare @tbl_product_attributes table (
                                        product_FK int,
                                        attribute_FK int,
                                        attribute_value varchar(64))
insert into @tbl_product_attributes
values
(1,5,'blah'),
(1,3,'blah blah'),
(2,1,'not sure'),
(2,3,'what should be here'),
(2,4,'but here is a'),
(3,5,'line of text'),
(3,4,'as a place holder')
declare @product_id nvarchar(4000)
set @product_id = '1,3'
if object_id ('tempdb..#staging') is not null
drop table #staging
select
    prod.id
    ,prod.title as ProductTitle
    ,'Attr' + cast(attr.id as char(8)) as AttributeID
    ,attr.title as AttributeTitle
    ,prodAttributes.attribute_value as EAV_AttributeValue
into #staging
from
    @tbl_products prod
inner join
    @tbl_product_attributes prodAttributes
    on prodAttributes.product_FK = prod.id
inner join
    @tbl_attributes attr on
    attr.id = prodAttributes.attribute_FK
inner join
    string_split(@product_id,',') x
    on x.value = prod.id
DECLARE @DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE @ColumnName AS NVARCHAR(MAX)
--Get distinct values of the PIVOT Column 
SELECT @ColumnName= ISNULL(@ColumnName + ',','') 
       + QUOTENAME(AttributeID)
FROM (SELECT DISTINCT AttributeID FROM #staging) AS AttributeID
--Prepare the PIVOT query using the dynamic 
SET @DynamicPivotQuery = 
  N'
    SELECT ProductTitle,  ' + @ColumnName + '
    FROM #staging
    PIVOT(min(AttributeTitle) 
          FOR AttributeID IN (' + @ColumnName + ')) AS PVTTable'
--Execute the Dynamic Pivot Query
EXEC sp_executesql @DynamicPivotQuery
So, you would just create the proc on the top part...
create proc yourProc(@product_id nvarchar(4000))
as
select
    prod.id
    ,prod.title as ProductTitle
    ,attr.title as AttributeTitle
    ,prodAttributes.attribute_value as EAV_AttributeValue
from
    @tbl_products prod
inner join
    @tbl_product_attributes prodAttributes
    on prodAttributes.product_FK = prod.id
inner join
    @tbl_attributes attr on
    attr.id = prodAttributes.attribute_FK
where
    prod.id in (select * from string_split(@product_id,','))
NOTE: This can also be written more cleanly as a join
select
    prod.id
    ,prod.title as ProductTitle
    ,attr.title as AttributeTitle
    ,prodAttributes.attribute_value as EAV_AttributeValue
from
    @tbl_products prod
inner join
    @tbl_product_attributes prodAttributes
    on prodAttributes.product_FK = prod.id
inner join
    @tbl_attributes attr on
    attr.id = prodAttributes.attribute_FK
inner join
    string_split(@product_id,',') x
    on x.value = prod.id